diff options
author | Elliott Baron <ebaron@fedoraproject.org> | 2010-06-26 22:27:34 -0400 |
---|---|---|
committer | Elliott Baron <ebaron@fedoraproject.org> | 2010-06-26 22:27:34 -0400 |
commit | 4e112eca7750a4f530c986be55c178c43c16d3ea (patch) | |
tree | db140c4fe4db9945502398e4869707ca0346353e /org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core | |
parent | aa73b3f2503808e4b4029a73368a75b258d6f0dc (diff) | |
download | codan-4e112eca7750a4f530c986be55c178c43c16d3ea.tar.gz codan-4e112eca7750a4f530c986be55c178c43c16d3ea.tar.xz codan-4e112eca7750a4f530c986be55c178c43c16d3ea.zip |
* org.eclipse.cdt.codan.checkers.ui: Updated.
* org.eclipse.cdt.codan.checkers: Updated.
* org.eclipse.cdt.codan.core: Updated.
* org.eclipse.cdt.codan.ui: Updated.
* org.eclipse.cdt.codan.core.cxx: Added.
* org.eclipse.cdt.codan.extension/META-INF/MANIFEST.MF: Import org.eclipse.cdt.codan.core.cxx.model.
* org.eclipse.cdt.codan.extension/src/org/eclipse/cdt/codan/extension/checkers/AbstractPropSimChecker.java: Superclass moved.
Diffstat (limited to 'org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core')
32 files changed, 4291 insertions, 353 deletions
diff --git a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CVS/Entries b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CVS/Entries index 49bf43c..9771946 100644 --- a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CVS/Entries +++ b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CVS/Entries @@ -1,5 +1,8 @@ -/CheckersRegisry.java/1.3/Wed Dec 16 21:48:48 2009// -/CodanBuilder.java/1.3/Wed Dec 16 21:48:48 2009// -/CodanPreferencesLoader.java/1.1/Wed Sep 23 23:29:36 2009// -/CodeAnlysisNature.java/1.1/Sat Aug 22 21:16:49 2009// +/CharOperation.java/1.2/Thu Jun 3 17:01:53 2010//TCDT_7_0_0 +/CheckersRegistry.java/1.3/Thu Jun 3 17:01:53 2010//TCDT_7_0_0 +/CodanApplication.java/1.7/Sun Jun 27 01:30:42 2010//TCDT_7_0_0 +/CodanBuilder.java/1.12/Sun Jun 27 01:30:42 2010//TCDT_7_0_0 +/CodanPreferencesLoader.java/1.8/Sun Jun 27 01:30:42 2010//TCDT_7_0_0 +/CodeAnlysisNature.java/1.4/Sun Jun 27 01:30:42 2010//TCDT_7_0_0 +D/cfg//// D/model//// diff --git a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CVS/Tag b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CVS/Tag new file mode 100644 index 0000000..49a449a --- /dev/null +++ b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CVS/Tag @@ -0,0 +1 @@ +NCDT_7_0_0 diff --git a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CharOperation.java b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CharOperation.java new file mode 100644 index 0000000..7790814 --- /dev/null +++ b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CharOperation.java @@ -0,0 +1,2713 @@ +/******************************************************************************* + * Copyright (c) 2010 Alena Laskavaia and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alena Laskavaia - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.internal.core; + +/** + * This class is a collection of helper methods to manipulate char arrays. + * + * @since 2.1 + */ +public final class CharOperation { + /** + * Constant for an empty char array + */ + public static final char[] NO_CHAR = new char[0]; + /** + * Constant for an empty char array with two dimensions. + */ + public static final char[][] NO_CHAR_CHAR = new char[0][]; + + /** + * Answers a new array with appending the suffix character at the end of the + * array. + * <br> + * <br> + * For example:<br> + * <ol> + * <li><pre> + * array = { 'a', 'b' } + * suffix = 'c' + * => result = { 'a', 'b' , 'c' } + * </pre> + * </li> + * <li><pre> + * array = null + * suffix = 'c' + * => result = { 'c' } + * </pre></li> + * </ol> + * + * @param array + * the array that is concanated with the suffix character + * @param suffix + * the suffix character + * @return the new array + */ + public static final char[] append(char[] array, char suffix) { + if (array == null) + return new char[] { suffix }; + int length = array.length; + System.arraycopy(array, 0, array = new char[length + 1], 0, length); + array[length] = suffix; + return array; + } + + /** + * Append the given subarray to the target array starting at the given index + * in the target array. + * The start of the subarray is inclusive, the end is exclusive. + * Answers a new target array if it needs to grow, otherwise answers the + * same target array. + * <br> + * For example:<br> + * <ol> + * <li><pre> + * target = { 'a', 'b', '0' } + * index = 2 + * array = { 'c', 'd' } + * start = 0 + * end = 1 + * => result = { 'a', 'b' , 'c' } + * </pre> + * </li> + * <li><pre> + * target = { 'a', 'b' } + * index = 2 + * array = { 'c', 'd' } + * start = 0 + * end = 1 + * => result = { 'a', 'b' , 'c', '0', '0' , '0' } (new array) + * </pre></li> + * <li><pre> + * target = { 'a', 'b', 'c' } + * index = 1 + * array = { 'c', 'd', 'e', 'f' } + * start = 1 + * end = 4 + * => result = { 'a', 'd' , 'e', 'f', '0', '0', '0', '0' } (new array) + * </pre></li> + * </ol> + * + * @param target + * the given target + * @param index + * the given index + * @param array + * the given array + * @param start + * the given start index + * @param end + * the given end index + * + * @return the new array + * @throws NullPointerException + * if the target array is null + */ + public static final char[] append(char[] target, int index, char[] array, + int start, int end) { + int targetLength = target.length; + int subLength = end - start; + int newTargetLength = subLength + index; + if (newTargetLength > targetLength) { + System.arraycopy(target, 0, target = new char[newTargetLength * 2], + 0, index); + } + System.arraycopy(array, start, target, index, subLength); + return target; + } + + /** + * Answers the concatenation of the two arrays. It answers null if the two + * arrays are null. + * If the first array is null, then the second array is returned. + * If the second array is null, then the first array is returned. + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * first = null + * second = null + * => result = null + * </pre> + * </li> + * <li><pre> + * first = { { ' a' } } + * second = null + * => result = { { ' a' } } + * </pre> + * </li> + * <li><pre> + * first = null + * second = { { ' a' } } + * => result = { { ' a' } } + * </pre> + * </li> + * <li><pre> + * first = { { ' b' } } + * second = { { ' a' } } + * => result = { { ' b' }, { ' a' } } + * </pre> + * </li> + * </ol> + * + * @param first + * the first array to concatenate + * @param second + * the second array to concatenate + * @return the concatenation of the two arrays, or null if the two arrays + * are null. + */ + public static final char[][] arrayConcat(char[][] first, char[][] second) { + if (first == null) + return second; + if (second == null) + return first; + int length1 = first.length; + int length2 = second.length; + char[][] result = new char[length1 + length2][]; + System.arraycopy(first, 0, result, 0, length1); + System.arraycopy(second, 0, result, length1, length2); + return result; + } + + /** + * Answers a new array adding the second array at the end of first array. + * It answers null if the first and second are null. + * If the first array is null, then a new array char[][] is created with + * second. + * If the second array is null, then the first array is returned. + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * first = null + * second = { 'a' } + * => result = { { ' a' } } + * </pre> + * <li><pre> + * first = { { ' a' } } + * second = null + * => result = { { ' a' } } + * </pre> + * </li> + * <li><pre> + * first = { { ' a' } } + * second = { ' b' } + * => result = { { ' a' } , { ' b' } } + * </pre> + * </li> + * </ol> + * + * @param first + * the first array to concatenate + * @param second + * the array to add at the end of the first array + * @return a new array adding the second array at the end of first array, or + * null if the two arrays are null. + */ + public static final char[][] arrayConcat(char[][] first, char[] second) { + if (second == null) + return first; + if (first == null) + return new char[][] { second }; + int length = first.length; + char[][] result = new char[length + 1][]; + System.arraycopy(first, 0, result, 0, length); + result[length] = second; + return result; + } + + /** + * Compares the contents of the two arrays array and prefix. Returns + * <ul> + * <li>zero if the array starts with the prefix contents</li> + * <li>the difference between the first two characters that are not equal + * </li> + * <li>one if array length is lower than the prefix length and that the + * prefix starts with the + * array contents.</li> + * </ul> + * <p> + * For example: + * <ol> + * <li><pre> + * array = null + * prefix = null + * => result = NullPointerException + * </pre> + * </li> + * <li><pre> + * array = { 'a', 'b', 'c', 'd', 'e' } + * prefix = { 'a', 'b', 'c'} + * => result = 0 + * </pre> + * </li> + * <li><pre> + * array = { 'a', 'b', 'c', 'd', 'e' } + * prefix = { 'a', 'B', 'c'} + * => result = 32 + * </pre> + * </li> + * <li><pre> + * array = { 'd', 'b', 'c', 'd', 'e' } + * prefix = { 'a', 'b', 'c'} + * => result = 3 + * </pre> + * </li> + * <li><pre> + * array = { 'a', 'b', 'c', 'd', 'e' } + * prefix = { 'd', 'b', 'c'} + * => result = -3 + * </pre> + * </li> + * <li><pre> + * array = { 'a', 'a', 'c', 'd', 'e' } + * prefix = { 'a', 'e', 'c'} + * => result = -4 + * </pre> + * </li> + * </ol> + * </p> + * + * @param array + * the given array + * @param prefix + * the given prefix + * @return the result of the comparison + * @exception NullPointerException + * if either array or prefix is null + */ + public static final int compareWith(char[] array, char[] prefix) { + int arrayLength = array.length; + int prefixLength = prefix.length; + int min = Math.min(arrayLength, prefixLength); + int i = 0; + while (min-- != 0) { + char c1 = array[i]; + char c2 = prefix[i++]; + if (c1 != c2) + return c1 - c2; + } + if (prefixLength == i) + return 0; + return 1; + } + + /** + * Answers the concatenation of the two arrays. It answers null if the two + * arrays are null. + * If the first array is null, then the second array is returned. + * If the second array is null, then the first array is returned. + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * first = null + * second = { 'a' } + * => result = { ' a' } + * </pre> + * </li> + * <li><pre> + * first = { ' a' } + * second = null + * => result = { ' a' } + * </pre> + * </li> + * <li><pre> + * first = { ' a' } + * second = { ' b' } + * => result = { ' a' , ' b' } + * </pre> + * </li> + * </ol> + * + * @param first + * the first array to concatenate + * @param second + * the second array to concatenate + * @return the concatenation of the two arrays, or null if the two arrays + * are null. + */ + public static final char[] concat(char[] first, char[] second) { + if (first == null) + return second; + if (second == null) + return first; + int length1 = first.length; + int length2 = second.length; + char[] result = new char[length1 + length2]; + System.arraycopy(first, 0, result, 0, length1); + System.arraycopy(second, 0, result, length1, length2); + return result; + } + + /** + * Answers the concatenation of the three arrays. It answers null if the + * three arrays are null. + * If first is null, it answers the concatenation of second and third. + * If second is null, it answers the concatenation of first and third. + * If third is null, it answers the concatenation of first and second. + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * first = null + * second = { 'a' } + * third = { 'b' } + * => result = { ' a', 'b' } + * </pre> + * </li> + * <li><pre> + * first = { 'a' } + * second = null + * third = { 'b' } + * => result = { ' a', 'b' } + * </pre> + * </li> + * <li><pre> + * first = { 'a' } + * second = { 'b' } + * third = null + * => result = { ' a', 'b' } + * </pre> + * </li> + * <li><pre> + * first = null + * second = null + * third = null + * => result = null + * </pre> + * </li> + * <li><pre> + * first = { 'a' } + * second = { 'b' } + * third = { 'c' } + * => result = { 'a', 'b', 'c' } + * </pre> + * </li> + * </ol> + * + * @param first + * the first array to concatenate + * @param second + * the second array to concatenate + * @param third + * the third array to concatenate + * + * @return the concatenation of the three arrays, or null if the three + * arrays are null. + */ + public static final char[] concat(char[] first, char[] second, char[] third) { + if (first == null) + return concat(second, third); + if (second == null) + return concat(first, third); + if (third == null) + return concat(first, second); + int length1 = first.length; + int length2 = second.length; + int length3 = third.length; + char[] result = new char[length1 + length2 + length3]; + System.arraycopy(first, 0, result, 0, length1); + System.arraycopy(second, 0, result, length1, length2); + System.arraycopy(third, 0, result, length1 + length2, length3); + return result; + } + + /** + * Answers the concatenation of the two arrays inserting the separator + * character between the two arrays. + * It answers null if the two arrays are null. + * If the first array is null, then the second array is returned. + * If the second array is null, then the first array is returned. + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * first = null + * second = { 'a' } + * separator = '/' + * => result = { ' a' } + * </pre> + * </li> + * <li><pre> + * first = { ' a' } + * second = null + * separator = '/' + * => result = { ' a' } + * </pre> + * </li> + * <li><pre> + * first = { ' a' } + * second = { ' b' } + * separator = '/' + * => result = { ' a' , '/', 'b' } + * </pre> + * </li> + * </ol> + * + * @param first + * the first array to concatenate + * @param second + * the second array to concatenate + * @param separator + * the character to insert + * @return the concatenation of the two arrays inserting the separator + * character + * between the two arrays , or null if the two arrays are null. + */ + public static final char[] concat(char[] first, char[] second, + char separator) { + if (first == null) + return second; + if (second == null) + return first; + int length1 = first.length; + if (length1 == 0) + return second; + int length2 = second.length; + if (length2 == 0) + return first; + char[] result = new char[length1 + length2 + 1]; + System.arraycopy(first, 0, result, 0, length1); + result[length1] = separator; + System.arraycopy(second, 0, result, length1 + 1, length2); + return result; + } + + /** + * Answers the concatenation of the three arrays inserting the sep1 + * character between the + * two arrays and sep2 between the last two. + * It answers null if the three arrays are null. + * If the first array is null, then it answers the concatenation of second + * and third inserting + * the sep2 character between them. + * If the second array is null, then it answers the concatenation of first + * and third inserting + * the sep1 character between them. + * If the third array is null, then it answers the concatenation of first + * and second inserting + * the sep1 character between them. + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * first = null + * sep1 = '/' + * second = { 'a' } + * sep2 = ':' + * third = { 'b' } + * => result = { ' a' , ':', 'b' } + * </pre> + * </li> + * <li><pre> + * first = { 'a' } + * sep1 = '/' + * second = null + * sep2 = ':' + * third = { 'b' } + * => result = { ' a' , '/', 'b' } + * </pre> + * </li> + * <li><pre> + * first = { 'a' } + * sep1 = '/' + * second = { 'b' } + * sep2 = ':' + * third = null + * => result = { ' a' , '/', 'b' } + * </pre> + * </li> + * <li><pre> + * first = { 'a' } + * sep1 = '/' + * second = { 'b' } + * sep2 = ':' + * third = { 'c' } + * => result = { ' a' , '/', 'b' , ':', 'c' } + * </pre> + * </li> + * </ol> + * + * @param first + * the first array to concatenate + * @param sep1 + * the character to insert + * @param second + * the second array to concatenate + * @param sep2 + * the character to insert + * @param third + * the second array to concatenate + * @return the concatenation of the three arrays inserting the sep1 + * character between the + * two arrays and sep2 between the last two. + */ + public static final char[] concat(char[] first, char sep1, char[] second, + char sep2, char[] third) { + if (first == null) + return concat(second, third, sep2); + if (second == null) + return concat(first, third, sep1); + if (third == null) + return concat(first, second, sep1); + int length1 = first.length; + int length2 = second.length; + int length3 = third.length; + char[] result = new char[length1 + length2 + length3 + 2]; + System.arraycopy(first, 0, result, 0, length1); + result[length1] = sep1; + System.arraycopy(second, 0, result, length1 + 1, length2); + result[length1 + length2 + 1] = sep2; + System.arraycopy(third, 0, result, length1 + length2 + 2, length3); + return result; + } + + /** + * Answers a new array with prepending the prefix character and appending + * the suffix + * character at the end of the array. If array is null, it answers a new + * array containing the + * prefix and the suffix characters. + * <br> + * <br> + * For example:<br> + * <ol> + * <li><pre> + * prefix = 'a' + * array = { 'b' } + * suffix = 'c' + * => result = { 'a', 'b' , 'c' } + * </pre> + * </li> + * <li><pre> + * prefix = 'a' + * array = null + * suffix = 'c' + * => result = { 'a', 'c' } + * </pre></li> + * </ol> + * + * @param prefix + * the prefix character + * @param array + * the array that is concanated with the prefix and suffix + * characters + * @param suffix + * the suffix character + * @return the new array + */ + public static final char[] concat(char prefix, char[] array, char suffix) { + if (array == null) + return new char[] { prefix, suffix }; + int length = array.length; + char[] result = new char[length + 2]; + result[0] = prefix; + System.arraycopy(array, 0, result, 1, length); + result[length + 1] = suffix; + return result; + } + + /** + * Answers the concatenation of the given array parts using the given + * separator between each + * part and appending the given name at the end. + * <br> + * <br> + * For example:<br> + * <ol> + * <li><pre> + * name = { 'c' } + * array = { { 'a' }, { 'b' } } + * separator = '.' + * => result = { 'a', '.', 'b' , '.', 'c' } + * </pre> + * </li> + * <li><pre> + * name = null + * array = { { 'a' }, { 'b' } } + * separator = '.' + * => result = { 'a', '.', 'b' } + * </pre></li> + * <li><pre> + * name = { ' c' } + * array = null + * separator = '.' + * => result = { 'c' } + * </pre></li> + * </ol> + * + * @param name + * the given name + * @param array + * the given array + * @param separator + * the given separator + * @return the concatenation of the given array parts using the given + * separator between each + * part and appending the given name at the end + */ + public static final char[] concatWith(char[] name, char[][] array, + char separator) { + int nameLength = name == null ? 0 : name.length; + if (nameLength == 0) + return concatWith(array, separator); + if (array == null) + return name; + final int length = array.length; + if (length == 0) + return name; + int size = nameLength; + int index = length; + while (--index >= 0) + if (array[index].length > 0) + size += array[index].length + 1; + char[] result = new char[size]; + index = size; + for (int i = length - 1; i >= 0; i--) { + int subLength = array[i].length; + if (subLength > 0) { + index -= subLength; + System.arraycopy(array[i], 0, result, index, subLength); + result[--index] = separator; + } + } + System.arraycopy(name, 0, result, 0, nameLength); + return result; + } + + /** + * Answers the concatenation of the given array parts using the given + * separator between each + * part and appending the given name at the end. + * <br> + * <br> + * For example:<br> + * <ol> + * <li><pre> + * name = { 'c' } + * array = { { 'a' }, { 'b' } } + * separator = '.' + * => result = { 'a', '.', 'b' , '.', 'c' } + * </pre> + * </li> + * <li><pre> + * name = null + * array = { { 'a' }, { 'b' } } + * separator = '.' + * => result = { 'a', '.', 'b' } + * </pre></li> + * <li><pre> + * name = { ' c' } + * array = null + * separator = '.' + * => result = { 'c' } + * </pre></li> + * </ol> + * + * @param array + * the given array + * @param name + * the given name + * @param separator + * the given separator + * @return the concatenation of the given array parts using the given + * separator between each + * part and appending the given name at the end + */ + public static final char[] concatWith(char[][] array, char[] name, + char separator) { + int nameLength = name == null ? 0 : name.length; + if (nameLength == 0) + return concatWith(array, separator); + if (array == null) + return name; + final int length = array.length; + if (length == 0) + return name; + int size = nameLength; + int index = length; + while (--index >= 0) + if (array[index].length > 0) + size += array[index].length + 1; + char[] result = new char[size]; + index = 0; + for (int i = 0; i < length; i++) { + int subLength = array[i].length; + if (subLength > 0) { + System.arraycopy(array[i], 0, result, index, subLength); + index += subLength; + result[index++] = separator; + } + } + System.arraycopy(name, 0, result, index, nameLength); + return result; + } + + /** + * Answers the concatenation of the given array parts using the given + * separator between each part. + * <br> + * <br> + * For example:<br> + * <ol> + * <li><pre> + * array = { { 'a' }, { 'b' } } + * separator = '.' + * => result = { 'a', '.', 'b' } + * </pre> + * </li> + * <li><pre> + * array = null + * separator = '.' + * => result = { } + * </pre></li> + * </ol> + * + * @param array + * the given array + * @param separator + * the given separator + * @return the concatenation of the given array parts using the given + * separator between each part + */ + public static final char[] concatWith(char[][] array, char separator) { + if (array == null) + return CharOperation.NO_CHAR; + int length = array.length; + if (length == 0) + return CharOperation.NO_CHAR; + int size = length - 1; + int index = length; + while (--index >= 0) { + if (array[index].length == 0) + size--; + else + size += array[index].length; + } + if (size <= 0) + return CharOperation.NO_CHAR; + char[] result = new char[size]; + index = length; + while (--index >= 0) { + length = array[index].length; + if (length > 0) { + System.arraycopy(array[index], 0, result, (size -= length), + length); + if (--size >= 0) + result[size] = separator; + } + } + return result; + } + + /** + * Answers true if the array contains an occurrence of character, false + * otherwise. + * + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * character = 'c' + * array = { { ' a' }, { ' b' } } + * result => false + * </pre> + * </li> + * <li><pre> + * character = 'a' + * array = { { ' a' }, { ' b' } } + * result => true + * </pre> + * </li> + * </ol> + * + * @param character + * the character to search + * @param array + * the array in which the search is done + * @return true if the array contains an occurrence of character, false + * otherwise. + * @exception NullPointerException + * if array is null. + */ + public static final boolean contains(char character, char[][] array) { + for (int i = array.length; --i >= 0;) { + char[] subarray = array[i]; + for (int j = subarray.length; --j >= 0;) + if (subarray[j] == character) + return true; + } + return false; + } + + /** + * Answers true if the array contains an occurrence of character, false + * otherwise. + * + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * character = 'c' + * array = { ' b' } + * result => false + * </pre> + * </li> + * <li><pre> + * character = 'a' + * array = { ' a' , ' b' } + * result => true + * </pre> + * </li> + * </ol> + * + * @param character + * the character to search + * @param array + * the array in which the search is done + * @return true if the array contains an occurrence of character, false + * otherwise. + * @exception NullPointerException + * if array is null. + */ + public static final boolean contains(char character, char[] array) { + for (int i = array.length; --i >= 0;) + if (array[i] == character) + return true; + return false; + } + + /** + * Answers a deep copy of the toCopy array. + * + * @param toCopy + * the array to copy + * @return a deep copy of the toCopy array. + */ + public static final char[][] deepCopy(char[][] toCopy) { + int toCopyLength = toCopy.length; + char[][] result = new char[toCopyLength][]; + for (int i = 0; i < toCopyLength; i++) { + char[] toElement = toCopy[i]; + int toElementLength = toElement.length; + char[] resultElement = new char[toElementLength]; + System.arraycopy(toElement, 0, resultElement, 0, toElementLength); + result[i] = resultElement; + } + return result; + } + + /** + * Return true if array ends with the sequence of characters contained in + * toBeFound, + * otherwise false. + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * array = { 'a', 'b', 'c', 'd' } + * toBeFound = { 'b', 'c' } + * result => false + * </pre> + * </li> + * <li><pre> + * array = { 'a', 'b', 'c' } + * toBeFound = { 'b', 'c' } + * result => true + * </pre> + * </li> + * </ol> + * + * @param array + * the array to check + * @param toBeFound + * the array to find + * @return true if array ends with the sequence of characters contained in + * toBeFound, + * otherwise false. + * @exception NullPointerException + * if array is null or toBeFound is null + */ + public static final boolean endsWith(char[] array, char[] toBeFound) { + int i = toBeFound.length; + int j = array.length - i; + if (j < 0) + return false; + while (--i >= 0) + if (toBeFound[i] != array[i + j]) + return false; + return true; + } + + /** + * Answers true if the two arrays are identical character by character, + * otherwise false. + * The equality is case sensitive. + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * first = null + * second = null + * result => true + * </pre> + * </li> + * <li><pre> + * first = { { } } + * second = null + * result => false + * </pre> + * </li> + * <li><pre> + * first = { { 'a' } } + * second = { { 'a' } } + * result => true + * </pre> + * </li> + * <li><pre> + * first = { { 'A' } } + * second = { { 'a' } } + * result => false + * </pre> + * </li> + * </ol> + * + * @param first + * the first array + * @param second + * the second array + * @return true if the two arrays are identical character by character, + * otherwise false + */ + public static final boolean equals(char[][] first, char[][] second) { + if (first == second) + return true; + if (first == null || second == null) + return false; + if (first.length != second.length) + return false; + for (int i = first.length; --i >= 0;) + if (!equals(first[i], second[i])) + return false; + return true; + } + + /** + * If isCaseSensite is true, answers true if the two arrays are identical + * character + * by character, otherwise false. + * If it is false, answers true if the two arrays are identical character by + * character without checking the case, otherwise false. + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * first = null + * second = null + * isCaseSensitive = true + * result => true + * </pre> + * </li> + * <li><pre> + * first = { { } } + * second = null + * isCaseSensitive = true + * result => false + * </pre> + * </li> + * <li><pre> + * first = { { 'A' } } + * second = { { 'a' } } + * isCaseSensitive = true + * result => false + * </pre> + * </li> + * <li><pre> + * first = { { 'A' } } + * second = { { 'a' } } + * isCaseSensitive = false + * result => true + * </pre> + * </li> + * </ol> + * + * @param first + * the first array + * @param second + * the second array + * @param isCaseSensitive + * check whether or not the equality should be case sensitive + * @return true if the two arrays are identical character by character + * according to the value + * of isCaseSensitive, otherwise false + */ + public static final boolean equals(char[][] first, char[][] second, + boolean isCaseSensitive) { + if (isCaseSensitive) { + return equals(first, second); + } + if (first == second) + return true; + if (first == null || second == null) + return false; + if (first.length != second.length) + return false; + for (int i = first.length; --i >= 0;) + if (!equals(first[i], second[i], false)) + return false; + return true; + } + + /** + * Answers true if the two arrays are identical character by character, + * otherwise false. + * The equality is case sensitive. + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * first = null + * second = null + * result => true + * </pre> + * </li> + * <li><pre> + * first = { } + * second = null + * result => false + * </pre> + * </li> + * <li><pre> + * first = { 'a' } + * second = { 'a' } + * result => true + * </pre> + * </li> + * <li><pre> + * first = { 'a' } + * second = { 'A' } + * result => false + * </pre> + * </li> + * </ol> + * + * @param first + * the first array + * @param second + * the second array + * @return true if the two arrays are identical character by character, + * otherwise false + */ + public static final boolean equals(char[] first, char[] second) { + if (first == second) + return true; + if (first == null || second == null) + return false; + if (first.length != second.length) + return false; + for (int i = first.length; --i >= 0;) + if (first[i] != second[i]) + return false; + return true; + } + + /** + * If isCaseSensite is true, answers true if the two arrays are identical + * character + * by character, otherwise false. + * If it is false, answers true if the two arrays are identical character by + * character without checking the case, otherwise false. + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * first = null + * second = null + * isCaseSensitive = true + * result => true + * </pre> + * </li> + * <li><pre> + * first = { } + * second = null + * isCaseSensitive = true + * result => false + * </pre> + * </li> + * <li><pre> + * first = { 'A' } + * second = { 'a' } + * isCaseSensitive = true + * result => false + * </pre> + * </li> + * <li><pre> + * first = { 'A' } + * second = { 'a' } + * isCaseSensitive = false + * result => true + * </pre> + * </li> + * </ol> + * + * @param first + * the first array + * @param second + * the second array + * @param isCaseSensitive + * check whether or not the equality should be case sensitive + * @return true if the two arrays are identical character by character + * according to the value + * of isCaseSensitive, otherwise false + */ + public static final boolean equals(char[] first, char[] second, + boolean isCaseSensitive) { + if (isCaseSensitive) { + return equals(first, second); + } + if (first == second) + return true; + if (first == null || second == null) + return false; + if (first.length != second.length) + return false; + for (int i = first.length; --i >= 0;) + if (Character.toLowerCase(first[i]) != Character + .toLowerCase(second[i])) + return false; + return true; + } + + /** + * If isCaseSensite is true, the equality is case sensitive, otherwise it is + * case insensitive. + * + * Answers true if the name contains the fragment at the starting index + * startIndex, otherwise false. + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * fragment = { 'b', 'c' , 'd' } + * name = { 'a', 'b', 'c' , 'd' } + * startIndex = 1 + * isCaseSensitive = true + * result => true + * </pre> + * </li> + * <li><pre> + * fragment = { 'b', 'c' , 'd' } + * name = { 'a', 'b', 'C' , 'd' } + * startIndex = 1 + * isCaseSensitive = true + * result => false + * </pre> + * </li> + * <li><pre> + * fragment = { 'b', 'c' , 'd' } + * name = { 'a', 'b', 'C' , 'd' } + * startIndex = 0 + * isCaseSensitive = false + * result => false + * </pre> + * </li> + * <li><pre> + * fragment = { 'b', 'c' , 'd' } + * name = { 'a', 'b'} + * startIndex = 0 + * isCaseSensitive = true + * result => false + * </pre> + * </li> + * </ol> + * + * @param fragment + * the fragment to check + * @param name + * the array to check + * @param startIndex + * the starting index + * @param isCaseSensitive + * check whether or not the equality should be case sensitive + * @return true if the name contains the fragment at the starting index + * startIndex according to the + * value of isCaseSensitive, otherwise false. + * @exception NullPointerException + * if fragment or name is null. + */ + public static final boolean fragmentEquals(char[] fragment, char[] name, + int startIndex, boolean isCaseSensitive) { + int max = fragment.length; + if (name.length < max + startIndex) + return false; + if (isCaseSensitive) { + for (int i = max; --i >= 0;) + // assumes the prefix is not larger than the name + if (fragment[i] != name[i + startIndex]) + return false; + return true; + } + for (int i = max; --i >= 0;) + // assumes the prefix is not larger than the name + if (Character.toLowerCase(fragment[i]) != Character + .toLowerCase(name[i + startIndex])) + return false; + return true; + } + + /** + * Answers a hashcode for the array + * + * @param array + * the array for which a hashcode is required + * @return the hashcode + * @exception NullPointerException + * if array is null + */ + public static final int hashCode(char[] array) { + int hash = 0; + int offset = 0; + int length = array.length; + if (length < 16) { + for (int i = length; i > 0; i--) + hash = (hash * 37) + array[offset++]; + } else { + // only sample some characters + int skip = length / 8; + for (int i = length; i > 0; i -= skip, offset += skip) + hash = (hash * 39) + array[offset]; + } + return hash & 0x7FFFFFFF; + } + + /** + * Answers true if c is a whitespace according to the JLS (\u000a, + * \u000c, \u000d, \u0009), otherwise false. + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * c = ' ' + * result => true + * </pre> + * </li> + * <li><pre> + * c = '\u3000' + * result => false + * </pre> + * </li> + * </ol> + * + * @param c + * the character to check + * @return true if c is a whitespace according to the JLS, otherwise false. + */ + public static boolean isWhitespace(char c) { + switch (c) { + case 10: /* \ u000a: LINE FEED */ + case 12: /* \ u000c: FORM FEED */ + case 13: /* \ u000d: CARRIAGE RETURN */ + case 32: /* \ u0020: SPACE */ + case 9: /* \ u0009: HORIZONTAL TABULATION */ + return true; + default: + return false; + } + } + + /** + * Answers the first index in the array for which the corresponding + * character is + * equal to toBeFound. Answers -1 if no occurrence of this character is + * found. + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * toBeFound = 'c' + * array = { ' a', 'b', 'c', 'd' } + * result => 2 + * </pre> + * </li> + * <li><pre> + * toBeFound = 'e' + * array = { ' a', 'b', 'c', 'd' } + * result => -1 + * </pre> + * </li> + * </ol> + * + * @param toBeFound + * the character to search + * @param array + * the array to be searched + * @return the first index in the array for which the corresponding + * character is + * equal to toBeFound, -1 otherwise + * @exception NullPointerException + * if array is null + */ + public static final int indexOf(char toBeFound, char[] array) { + for (int i = 0; i < array.length; i++) + if (toBeFound == array[i]) + return i; + return -1; + } + + /** + * Answers the first index in the array for which the corresponding + * character is + * equal to toBeFound starting the search at index start. + * Answers -1 if no occurrence of this character is found. + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * toBeFound = 'c' + * array = { ' a', 'b', 'c', 'd' } + * start = 2 + * result => 2 + * </pre> + * </li> + * <li><pre> + * toBeFound = 'c' + * array = { ' a', 'b', 'c', 'd' } + * start = 3 + * result => -1 + * </pre> + * </li> + * <li><pre> + * toBeFound = 'e' + * array = { ' a', 'b', 'c', 'd' } + * start = 1 + * result => -1 + * </pre> + * </li> + * </ol> + * + * @param toBeFound + * the character to search + * @param array + * the array to be searched + * @param start + * the starting index + * @return the first index in the array for which the corresponding + * character is + * equal to toBeFound, -1 otherwise + * @exception NullPointerException + * if array is null + * @exception ArrayIndexOutOfBoundsException + * if start is lower than 0 + */ + public static final int indexOf(char toBeFound, char[] array, int start) { + for (int i = start; i < array.length; i++) + if (toBeFound == array[i]) + return i; + return -1; + } + + /** + * Answers the last index in the array for which the corresponding character + * is + * equal to toBeFound starting from the end of the array. + * Answers -1 if no occurrence of this character is found. + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * toBeFound = 'c' + * array = { ' a', 'b', 'c', 'd' , 'c', 'e' } + * result => 4 + * </pre> + * </li> + * <li><pre> + * toBeFound = 'e' + * array = { ' a', 'b', 'c', 'd' } + * result => -1 + * </pre> + * </li> + * </ol> + * + * @param toBeFound + * the character to search + * @param array + * the array to be searched + * @return the last index in the array for which the corresponding character + * is + * equal to toBeFound starting from the end of the array, -1 + * otherwise + * @exception NullPointerException + * if array is null + */ + public static final int lastIndexOf(char toBeFound, char[] array) { + for (int i = array.length; --i >= 0;) + if (toBeFound == array[i]) + return i; + return -1; + } + + /** + * Answers the last index in the array for which the corresponding character + * is + * equal to toBeFound stopping at the index startIndex. + * Answers -1 if no occurrence of this character is found. + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * toBeFound = 'c' + * array = { ' a', 'b', 'c', 'd' } + * startIndex = 2 + * result => 2 + * </pre> + * </li> + * <li><pre> + * toBeFound = 'c' + * array = { ' a', 'b', 'c', 'd', 'e' } + * startIndex = 3 + * result => -1 + * </pre> + * </li> + * <li><pre> + * toBeFound = 'e' + * array = { ' a', 'b', 'c', 'd' } + * startIndex = 0 + * result => -1 + * </pre> + * </li> + * </ol> + * + * @param toBeFound + * the character to search + * @param array + * the array to be searched + * @param startIndex + * the stopping index + * @return the last index in the array for which the corresponding character + * is + * equal to toBeFound stopping at the index startIndex, -1 otherwise + * @exception NullPointerException + * if array is null + * @exception ArrayIndexOutOfBoundsException + * if startIndex is lower than 0 + */ + public static final int lastIndexOf(char toBeFound, char[] array, + int startIndex) { + for (int i = array.length; --i >= startIndex;) + if (toBeFound == array[i]) + return i; + return -1; + } + + /** + * Answers the last index in the array for which the corresponding character + * is + * equal to toBeFound starting from endIndex to startIndex. + * Answers -1 if no occurrence of this character is found. + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * toBeFound = 'c' + * array = { ' a', 'b', 'c', 'd' } + * startIndex = 2 + * endIndex = 2 + * result => 2 + * </pre> + * </li> + * <li><pre> + * toBeFound = 'c' + * array = { ' a', 'b', 'c', 'd', 'e' } + * startIndex = 3 + * endIndex = 4 + * result => -1 + * </pre> + * </li> + * <li><pre> + * toBeFound = 'e' + * array = { ' a', 'b', 'c', 'd' } + * startIndex = 0 + * endIndex = 3 + * result => -1 + * </pre> + * </li> + * </ol> + * + * @param toBeFound + * the character to search + * @param array + * the array to be searched + * @param startIndex + * the stopping index + * @param endIndex + * the starting index + * @return the last index in the array for which the corresponding character + * is + * equal to toBeFound starting from endIndex to startIndex, -1 + * otherwise + * @exception NullPointerException + * if array is null + * @exception ArrayIndexOutOfBoundsException + * if endIndex is greater or equals to array length or + * starting is lower than 0 + */ + public static final int lastIndexOf(char toBeFound, char[] array, + int startIndex, int endIndex) { + for (int i = endIndex; --i >= startIndex;) + if (toBeFound == array[i]) + return i; + return -1; + } + + /** + * Answers the last portion of a name given a separator. + * <br> + * <br> + * For example, + * <pre> + * lastSegment("java.lang.Object".toCharArray(),'.') --> Object + * </pre> + * + * @param array + * the array + * @param separator + * the given separator + * @return the last portion of a name given a separator + * @exception NullPointerException + * if array is null + */ + final static public char[] lastSegment(char[] array, char separator) { + int pos = lastIndexOf(separator, array); + if (pos < 0) + return array; + return subarray(array, pos + 1, array.length); + } + + /** + * Answers true if the pattern matches the given name, false otherwise. This + * char[] pattern matching + * accepts wild-cards '*' and '?'. + * + * When not case sensitive, the pattern is assumed to already be lowercased, + * the + * name will be lowercased character per character as comparing. + * If name is null, the answer is false. + * If pattern is null, the answer is true if name is not null. + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * pattern = { '?', 'b', '*' } + * name = { 'a', 'b', 'c' , 'd' } + * isCaseSensitive = true + * result => true + * </pre> + * </li> + * <li><pre> + * pattern = { '?', 'b', '?' } + * name = { 'a', 'b', 'c' , 'd' } + * isCaseSensitive = true + * result => false + * </pre> + * </li> + * <li><pre> + * pattern = { 'b', '*' } + * name = { 'a', 'b', 'c' , 'd' } + * isCaseSensitive = true + * result => false + * </pre> + * </li> + * </ol> + * + * @param pattern + * the given pattern + * @param name + * the given name + * @param isCaseSensitive + * flag to know whether or not the matching should be case + * sensitive + * @return true if the pattern matches the given name, false otherwise + */ + public static final boolean match(char[] pattern, char[] name, + boolean isCaseSensitive) { + if (name == null) + return false; // null name cannot match + if (pattern == null) + return true; // null pattern is equivalent to '*' + return match(pattern, 0, pattern.length, name, 0, name.length, + isCaseSensitive, true); + } + + /** + * Answers true if the a sub-pattern matches the subpart of the given name, + * false otherwise. + * char[] pattern matching, accepting wild-cards '*' and '?'. Can match only + * subset of name/pattern. + * end positions are non-inclusive. + * The subpattern is defined by the patternStart and pattternEnd positions. + * When not case sensitive, the pattern is assumed to already be lowercased, + * the + * name will be lowercased character per character as comparing. + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * pattern = { '?', 'b', '*' } + * patternStart = 1 + * patternEnd = 3 + * name = { 'a', 'b', 'c' , 'd' } + * nameStart = 1 + * nameEnd = 4 + * isCaseSensitive = true + * result => true + * </pre> + * </li> + * <li><pre> + * pattern = { '?', 'b', '*' } + * patternStart = 1 + * patternEnd = 2 + * name = { 'a', 'b', 'c' , 'd' } + * nameStart = 1 + * nameEnd = 2 + * isCaseSensitive = true + * result => false + * </pre> + * </li> + * </ol> + * + * @param pattern + * the given pattern + * @param patternStart + * the given pattern start + * @param patternEnd + * the given pattern end + * @param name + * the given name + * @param nameStart + * the given name start + * @param nameEnd + * the given name end + * @param isCaseSensitive + * flag to know if the matching should be case sensitive + * @return true if the a sub-pattern matches the subpart of the given name, + * false otherwise + */ + public static final boolean match(char[] pattern, int patternStart, + int patternEnd, char[] name, int nameStart, int nameEnd, + boolean isCaseSensitive) { + return match(pattern, patternStart, patternEnd, name, nameStart, + nameEnd, isCaseSensitive, false); + } + + public static final boolean match(char[] pattern, int patternStart, + int patternEnd, char[] name, int nameStart, int nameEnd, + boolean isCaseSensitive, boolean allowEscaping) { + if (name == null) + return false; // null name cannot match + if (pattern == null) + return true; // null pattern is equivalent to '*' + int iPattern = patternStart; + int iName = nameStart; + if (patternEnd < 0) + patternEnd = pattern.length; + if (nameEnd < 0) + nameEnd = name.length; + /* check first segment */ + char patternChar = 0; + boolean isEscaped = false; + while ((iPattern < patternEnd) + && ((patternChar = pattern[iPattern]) != '*' || (patternChar == '*' && isEscaped))) { + if (allowEscaping && pattern[iPattern] == '\\' && !isEscaped) { + iPattern++; + isEscaped = true; + continue; + } else + isEscaped = false; + if (iName == nameEnd) + return false; + if (patternChar != (isCaseSensitive ? name[iName] : Character + .toLowerCase(name[iName])) && patternChar != '?') { + return false; + } + iName++; + iPattern++; + patternChar = 0; + } + /* check sequence of star+segment */ + int segmentStart; + if (patternChar == '*') { + segmentStart = ++iPattern; // skip star + } else { + segmentStart = 0; // force iName check + } + int prefixStart = iName; + checkSegment: while (iName < nameEnd) { + if (iPattern == patternEnd) { + iPattern = segmentStart; // mismatch - restart current segment + iName = ++prefixStart; + continue checkSegment; + } + /* segment is ending */ + if ((patternChar = pattern[iPattern]) == '*') { + segmentStart = ++iPattern; // skip start + if (segmentStart == patternEnd) { + return true; + } + prefixStart = iName; + continue checkSegment; + } + /* check current name character */ + if ((isCaseSensitive ? name[iName] : Character + .toLowerCase(name[iName])) != patternChar + && patternChar != '?') { + iPattern = segmentStart; // mismatch - restart current segment + iName = ++prefixStart; + continue checkSegment; + } + iName++; + iPattern++; + } + return (segmentStart == patternEnd) + || (iName == nameEnd && iPattern == patternEnd) + || (iPattern == patternEnd - 1 && pattern[iPattern] == '*'); + } + + /** + * Answers true if the pattern matches the filepath using the pathSepatator, + * false otherwise. + * + * Path char[] pattern matching, accepting wild-cards '**', '*' and '?' + * (using Ant directory tasks + * conventions, also see + * "http://jakarta.apache.org/ant/manual/dirtasks.html#defaultexcludes"). + * Path pattern matching is enhancing regular pattern matching in supporting + * extra rule where '**' represent + * any folder combination. + * Special rules: + * - foo\ is equivalent to foo\** + * - *.java is equivalent to **\*.java + * When not case sensitive, the pattern is assumed to already be lowercased, + * the + * name will be lowercased character per character as comparing. + * + * @param pattern + * the given pattern + * @param filepath + * the given path + * @param isCaseSensitive + * to find out whether or not the matching should be case + * sensitive + * @param pathSeparator + * the given path separator + * @return true if the pattern matches the filepath using the pathSepatator, + * false otherwise + */ + public static final boolean pathMatch(char[] pattern, char[] filepath, + boolean isCaseSensitive, char pathSeparator) { + if (filepath == null) + return false; // null name cannot match + if (pattern == null) + return true; // null pattern is equivalent to '*' + // special case: pattern foo is equivalent to **\foo (not absolute) + boolean freeLeadingDoubleStar; + // offsets inside pattern + int pSegmentStart, pLength = pattern.length; + freeLeadingDoubleStar = (pattern[0] != pathSeparator); + if (freeLeadingDoubleStar) { + pSegmentStart = 0; + } else { + pSegmentStart = 1; + } + int pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern, + pSegmentStart + 1); + if (pSegmentEnd < 0) + pSegmentEnd = pLength; + // special case: pattern foo\ is equivalent to foo\** + boolean freeTrailingDoubleStar = pattern[pLength - 1] == pathSeparator; + // offsets inside filepath + int fSegmentStart, fLength = filepath.length; + if (filepath[0] != pathSeparator) { + fSegmentStart = 0; + } else { + fSegmentStart = 1; + } + if (fSegmentStart != pSegmentStart) { + return false; // both must start with a separator or none. + } + int fSegmentEnd = CharOperation.indexOf(pathSeparator, filepath, + fSegmentStart + 1); + if (fSegmentEnd < 0) + fSegmentEnd = fLength; + // first segments + while (pSegmentStart < pLength + && !freeLeadingDoubleStar + && !(pSegmentEnd == pLength && freeTrailingDoubleStar || (pSegmentEnd == pSegmentStart + 2 + && pattern[pSegmentStart] == '*' && pattern[pSegmentStart + 1] == '*'))) { + if (fSegmentStart >= fLength) + return false; + if (!CharOperation.match(pattern, pSegmentStart, pSegmentEnd, + filepath, fSegmentStart, fSegmentEnd, isCaseSensitive)) { + return false; + } + // jump to next segment + pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern, + pSegmentStart = pSegmentEnd + 1); + // skip separator + if (pSegmentEnd < 0) + pSegmentEnd = pLength; + fSegmentEnd = CharOperation.indexOf(pathSeparator, filepath, + fSegmentStart = fSegmentEnd + 1); + // skip separator + if (fSegmentEnd < 0) + fSegmentEnd = fLength; + } + /* check sequence of doubleStar+segment */ + int pSegmentRestart; + if ((pSegmentStart >= pLength && freeTrailingDoubleStar) + || (pSegmentEnd == pSegmentStart + 2 + && pattern[pSegmentStart] == '*' && pattern[pSegmentStart + 1] == '*')) { + pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern, + pSegmentStart = pSegmentEnd + 1); + // skip separator + if (pSegmentEnd < 0) + pSegmentEnd = pLength; + pSegmentRestart = pSegmentStart; + } else { + if (pSegmentStart >= pLength) + return fSegmentStart >= fLength; // true if filepath is done too. + pSegmentRestart = 0; // force fSegmentStart check + } + int fSegmentRestart = fSegmentStart; + checkSegment: while (fSegmentStart < fLength) { + if (pSegmentStart >= pLength) { + if (freeTrailingDoubleStar) + return true; + // mismatch - restart current path segment + pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern, + pSegmentStart = pSegmentRestart); + if (pSegmentEnd < 0) + pSegmentEnd = pLength; + fSegmentRestart = CharOperation.indexOf(pathSeparator, + filepath, fSegmentRestart + 1); + // skip separator + if (fSegmentRestart < 0) { + fSegmentRestart = fLength; + } else { + fSegmentRestart++; + } + fSegmentEnd = CharOperation.indexOf(pathSeparator, filepath, + fSegmentStart = fSegmentRestart); + if (fSegmentEnd < 0) + fSegmentEnd = fLength; + continue checkSegment; + } + /* path segment is ending */ + if (pSegmentEnd == pSegmentStart + 2 + && pattern[pSegmentStart] == '*' + && pattern[pSegmentStart + 1] == '*') { + pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern, + pSegmentStart = pSegmentEnd + 1); + // skip separator + if (pSegmentEnd < 0) + pSegmentEnd = pLength; + pSegmentRestart = pSegmentStart; + fSegmentRestart = fSegmentStart; + if (pSegmentStart >= pLength) + return true; + continue checkSegment; + } + /* chech current path segment */ + if (!CharOperation.match(pattern, pSegmentStart, pSegmentEnd, + filepath, fSegmentStart, fSegmentEnd, isCaseSensitive)) { + // mismatch - restart current path segment + pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern, + pSegmentStart = pSegmentRestart); + if (pSegmentEnd < 0) + pSegmentEnd = pLength; + fSegmentRestart = CharOperation.indexOf(pathSeparator, + filepath, fSegmentRestart + 1); + // skip separator + if (fSegmentRestart < 0) { + fSegmentRestart = fLength; + } else { + fSegmentRestart++; + } + fSegmentEnd = CharOperation.indexOf(pathSeparator, filepath, + fSegmentStart = fSegmentRestart); + if (fSegmentEnd < 0) + fSegmentEnd = fLength; + continue checkSegment; + } + // jump to next segment + pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern, + pSegmentStart = pSegmentEnd + 1); + // skip separator + if (pSegmentEnd < 0) + pSegmentEnd = pLength; + fSegmentEnd = CharOperation.indexOf(pathSeparator, filepath, + fSegmentStart = fSegmentEnd + 1); + // skip separator + if (fSegmentEnd < 0) + fSegmentEnd = fLength; + } + return (pSegmentRestart >= pSegmentEnd) + || (fSegmentStart >= fLength && pSegmentStart >= pLength) + || (pSegmentStart == pLength - 2 + && pattern[pSegmentStart] == '*' && pattern[pSegmentStart + 1] == '*') + || (pSegmentStart == pLength && freeTrailingDoubleStar); + } + + /** + * Answers the number of occurrences of the given character in the given + * array, 0 if any. + * + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * toBeFound = 'b' + * array = { 'a' , 'b', 'b', 'a', 'b', 'a' } + * result => 3 + * </pre> + * </li> + * <li><pre> + * toBeFound = 'c' + * array = { 'a' , 'b', 'b', 'a', 'b', 'a' } + * result => 0 + * </pre> + * </li> + * </ol> + * + * @param toBeFound + * the given character + * @param array + * the given array + * @return the number of occurrences of the given character in the given + * array, 0 if any + * @exception NullPointerException + * if array is null + */ + public static final int occurencesOf(char toBeFound, char[] array) { + int count = 0; + for (char element : array) + if (toBeFound == element) + count++; + return count; + } + + /** + * Answers the number of occurrences of the given character in the given + * array starting + * at the given index, 0 if any. + * + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * toBeFound = 'b' + * array = { 'a' , 'b', 'b', 'a', 'b', 'a' } + * start = 2 + * result => 2 + * </pre> + * </li> + * <li><pre> + * toBeFound = 'c' + * array = { 'a' , 'b', 'b', 'a', 'b', 'a' } + * start = 0 + * result => 0 + * </pre> + * </li> + * </ol> + * + * @param toBeFound + * the given character + * @param array + * the given array + * @return the number of occurrences of the given character in the given + * array, 0 if any + * @exception NullPointerException + * if array is null + * @exception ArrayIndexOutOfBoundsException + * if start is lower than 0 + */ + public static final int occurencesOf(char toBeFound, char[] array, int start) { + int count = 0; + for (int i = start; i < array.length; i++) + if (toBeFound == array[i]) + count++; + return count; + } + + /** + * Answers true if the given name starts with the given prefix, false + * otherwise. + * The comparison is case sensitive. + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * prefix = { 'a' , 'b' } + * name = { 'a' , 'b', 'b', 'a', 'b', 'a' } + * result => true + * </pre> + * </li> + * <li><pre> + * prefix = { 'a' , 'c' } + * name = { 'a' , 'b', 'b', 'a', 'b', 'a' } + * result => false + * </pre> + * </li> + * </ol> + * + * @param prefix + * the given prefix + * @param name + * the given name + * @return true if the given name starts with the given prefix, false + * otherwise + * @exception NullPointerException + * if the given name is null or if the given prefix is null + */ + public static final boolean prefixEquals(char[] prefix, char[] name) { + int max = prefix.length; + if (name.length < max) + return false; + for (int i = max; --i >= 0;) + // assumes the prefix is not larger than the name + if (prefix[i] != name[i]) + return false; + return true; + } + + /** + * Answers true if the given name starts with the given prefix, false + * otherwise. + * isCaseSensitive is used to find out whether or not the comparison should + * be case sensitive. + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * prefix = { 'a' , 'B' } + * name = { 'a' , 'b', 'b', 'a', 'b', 'a' } + * isCaseSensitive = false + * result => true + * </pre> + * </li> + * <li><pre> + * prefix = { 'a' , 'B' } + * name = { 'a' , 'b', 'b', 'a', 'b', 'a' } + * isCaseSensitive = true + * result => false + * </pre> + * </li> + * </ol> + * + * @param prefix + * the given prefix + * @param name + * the given name + * @param isCaseSensitive + * to find out whether or not the comparison should be case + * sensitive + * @return true if the given name starts with the given prefix, false + * otherwise + * @exception NullPointerException + * if the given name is null or if the given prefix is null + */ + public static final boolean prefixEquals(char[] prefix, char[] name, + boolean isCaseSensitive) { + int max = prefix.length; + if (name.length < max) + return false; + if (isCaseSensitive) { + for (int i = max; --i >= 0;) + // assumes the prefix is not larger than the name + if (prefix[i] != name[i]) + return false; + return true; + } + for (int i = max; --i >= 0;) + // assumes the prefix is not larger than the name + if (Character.toLowerCase(prefix[i]) != Character + .toLowerCase(name[i])) + return false; + return true; + } + + /** + * Replace all occurrence of the character to be replaced with the + * remplacement character in the + * given array. + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * array = { 'a' , 'b', 'b', 'a', 'b', 'a' } + * toBeReplaced = 'b' + * replacementChar = 'a' + * result => No returned value, but array is now equals to { 'a' , 'a', 'a', + * 'a', 'a', 'a' } + * </pre> + * </li> + * <li><pre> + * array = { 'a' , 'b', 'b', 'a', 'b', 'a' } + * toBeReplaced = 'c' + * replacementChar = 'a' + * result => No returned value, but array is now equals to { 'a' , 'b', 'b', + * 'a', 'b', 'a' } + * </pre> + * </li> + * </ol> + * + * @param array + * the given array + * @param toBeReplaced + * the character to be replaced + * @param replacementChar + * the replacement character + * @exception NullPointerException + * if the given array is null + */ + public static final void replace(char[] array, char toBeReplaced, + char replacementChar) { + if (toBeReplaced != replacementChar) { + for (int i = 0, max = array.length; i < max; i++) { + if (array[i] == toBeReplaced) + array[i] = replacementChar; + } + } + } + + /** + * Answers a new array of characters with substitutions. No side-effect is + * operated on the original + * array, in case no substitution happened, then the result is the same as + * the + * original one. + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * array = { 'a' , 'b', 'b', 'a', 'b', 'a' } + * toBeReplaced = { 'b' } + * replacementChar = { 'a', 'a' } + * result => { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' } + * </pre> + * </li> + * <li><pre> + * array = { 'a' , 'b', 'b', 'a', 'b', 'a' } + * toBeReplaced = { 'c' } + * replacementChar = { 'a' } + * result => { 'a' , 'b', 'b', 'a', 'b', 'a' } + * </pre> + * </li> + * </ol> + * + * @param array + * the given array + * @param toBeReplaced + * characters to be replaced + * @param replacementChars + * the replacement characters + * @return a new array of characters with substitutions or the given array + * if none + * @exception NullPointerException + * if the given array is null + */ + public static final char[] replace(char[] array, char[] toBeReplaced, + char[] replacementChars) { + int max = array.length; + int replacedLength = toBeReplaced.length; + int replacementLength = replacementChars.length; + int[] starts = new int[5]; + int occurrenceCount = 0; + if (!equals(toBeReplaced, replacementChars)) { + next: for (int i = 0; i < max; i++) { + int j = 0; + while (j < replacedLength) { + if (i + j == max) + continue next; + if (array[i + j] != toBeReplaced[j++]) + continue next; + } + if (occurrenceCount == starts.length) { + System.arraycopy(starts, 0, + starts = new int[occurrenceCount * 2], 0, + occurrenceCount); + } + starts[occurrenceCount++] = i; + } + } + if (occurrenceCount == 0) + return array; + char[] result = new char[max + occurrenceCount + * (replacementLength - replacedLength)]; + int inStart = 0, outStart = 0; + for (int i = 0; i < occurrenceCount; i++) { + int offset = starts[i] - inStart; + System.arraycopy(array, inStart, result, outStart, offset); + inStart += offset; + outStart += offset; + System.arraycopy(replacementChars, 0, result, outStart, + replacementLength); + inStart += replacedLength; + outStart += replacementLength; + } + System.arraycopy(array, inStart, result, outStart, max - inStart); + return result; + } + + /** + * Return a new array which is the split of the given array using the given + * divider and triming each subarray to remove + * whitespaces equals to ' '. + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * divider = 'b' + * array = { 'a' , 'b', 'b', 'a', 'b', 'a' } + * result => { { 'a' }, { }, { 'a' }, { 'a' } } + * </pre> + * </li> + * <li><pre> + * divider = 'c' + * array = { 'a' , 'b', 'b', 'a', 'b', 'a' } + * result => { { 'a', 'b', 'b', 'a', 'b', 'a' } } + * </pre> + * </li> + * <li><pre> + * divider = 'b' + * array = { 'a' , ' ', 'b', 'b', 'a', 'b', 'a' } + * result => { { 'a' }, { }, { 'a' }, { 'a' } } + * </pre> + * </li> + * <li><pre> + * divider = 'c' + * array = { ' ', ' ', 'a' , 'b', 'b', 'a', 'b', 'a', ' ' } + * result => { { 'a', 'b', 'b', 'a', 'b', 'a' } } + * </pre> + * </li> + * </ol> + * + * @param divider + * the given divider + * @param array + * the given array + * @return a new array which is the split of the given array using the given + * divider and triming each subarray to remove + * whitespaces equals to ' ' + */ + public static final char[][] splitAndTrimOn(char divider, char[] array) { + if (array == null) + return NO_CHAR_CHAR; + final int length = array.length; + if (length == 0) + return NO_CHAR_CHAR; + int wordCount = 1; + for (int i = 0; i < length; i++) + if (array[i] == divider) + wordCount++; + char[][] split = new char[wordCount][]; + int last = 0, currentWord = 0; + for (int i = 0; i < length; i++) { + if (array[i] == divider) { + int start = last, end = i - 1; + while (start < i && array[start] == ' ') + start++; + while (end > start && array[end] == ' ') + end--; + split[currentWord] = new char[end - start + 1]; + System.arraycopy(array, start, split[currentWord++], 0, end + - start + 1); + last = i + 1; + } + } + int start = last, end = length - 1; + while (start < length && array[start] == ' ') + start++; + while (end > start && array[end] == ' ') + end--; + split[currentWord] = new char[end - start + 1]; + System.arraycopy(array, start, split[currentWord++], 0, end - start + 1); + return split; + } + + /** + * Return a new array which is the split of the given array using the given + * divider. + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * divider = 'b' + * array = { 'a' , 'b', 'b', 'a', 'b', 'a' } + * result => { { 'a' }, { }, { 'a' }, { 'a' } } + * </pre> + * </li> + * <li><pre> + * divider = 'c' + * array = { 'a' , 'b', 'b', 'a', 'b', 'a' } + * result => { { 'a', 'b', 'b', 'a', 'b', 'a' } } + * </pre> + * </li> + * <li><pre> + * divider = 'c' + * array = { ' ', ' ', 'a' , 'b', 'b', 'a', 'b', 'a', ' ' } + * result => { { ' ', 'a', 'b', 'b', 'a', 'b', 'a', ' ' } } + * </pre> + * </li> + * </ol> + * + * @param divider + * the given divider + * @param array + * the given array + * @return a new array which is the split of the given array using the given + * divider + */ + public static final char[][] splitOn(char divider, char[] array) { + if (array == null) + return NO_CHAR_CHAR; + final int length = array.length; + if (length == 0) + return NO_CHAR_CHAR; + int wordCount = 1; + for (int i = 0; i < length; i++) + if (array[i] == divider) + wordCount++; + char[][] split = new char[wordCount][]; + int last = 0, currentWord = 0; + for (int i = 0; i < length; i++) { + if (array[i] == divider) { + split[currentWord] = new char[i - last]; + System.arraycopy(array, last, split[currentWord++], 0, i - last); + last = i + 1; + } + } + split[currentWord] = new char[length - last]; + System.arraycopy(array, last, split[currentWord], 0, length - last); + return split; + } + + /** + * Return a new array which is the split of the given array using the given + * divider. The given end + * is exclusive and the given start is inclusive. + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * divider = 'b' + * array = { 'a' , 'b', 'b', 'a', 'b', 'a' } + * start = 2 + * end = 5 + * result => { { }, { }, { 'a' } } + * </pre> + * </li> + * </ol> + * + * @param divider + * the given divider + * @param array + * the given array + * @param start + * the given starting index + * @param end + * the given ending index + * @return a new array which is the split of the given array using the given + * divider + * @exception ArrayIndexOutOfBoundsException + * if start is lower than 0 or end is greater than the array + * length + */ + public static final char[][] splitOn(char divider, char[] array, int start, + int end) { + if (array == null) + return NO_CHAR_CHAR; + final int length = array.length; + if (length == 0 || start > end) + return NO_CHAR_CHAR; + int wordCount = 1; + for (int i = start; i < end; i++) + if (array[i] == divider) + wordCount++; + char[][] split = new char[wordCount][]; + int last = start, currentWord = 0; + for (int i = start; i < end; i++) { + if (array[i] == divider) { + split[currentWord] = new char[i - last]; + System.arraycopy(array, last, split[currentWord++], 0, i - last); + last = i + 1; + } + } + split[currentWord] = new char[end - last]; + System.arraycopy(array, last, split[currentWord], 0, end - last); + return split; + } + + /** + * Answers a new array which is a copy of the given array starting at the + * given start and + * ending at the given end. The given start is inclusive and the given end + * is exclusive. + * Answers null if start is greater than end, if start is lower than 0 or if + * end is greater + * than the length of the given array. If end equals -1, it is converted to + * the array length. + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * array = { { 'a' } , { 'b' } } + * start = 0 + * end = 1 + * result => { { 'a' } } + * </pre> + * </li> + * <li><pre> + * array = { { 'a' } , { 'b' } } + * start = 0 + * end = -1 + * result => { { 'a' }, { 'b' } } + * </pre> + * </li> + * </ol> + * + * @param array + * the given array + * @param start + * the given starting index + * @param end + * the given ending index + * @return a new array which is a copy of the given array starting at the + * given start and + * ending at the given end + * @exception NullPointerException + * if the given array is null + */ + public static final char[][] subarray(char[][] array, int start, int end) { + if (end == -1) + end = array.length; + if (start > end) + return null; + if (start < 0) + return null; + if (end > array.length) + return null; + char[][] result = new char[end - start][]; + System.arraycopy(array, start, result, 0, end - start); + return result; + } + + /** + * Answers a new array which is a copy of the given array starting at the + * given start and + * ending at the given end. The given start is inclusive and the given end + * is exclusive. + * Answers null if start is greater than end, if start is lower than 0 or if + * end is greater + * than the length of the given array. If end equals -1, it is converted to + * the array length. + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * array = { 'a' , 'b' } + * start = 0 + * end = 1 + * result => { 'a' } + * </pre> + * </li> + * <li><pre> + * array = { 'a', 'b' } + * start = 0 + * end = -1 + * result => { 'a' , 'b' } + * </pre> + * </li> + * </ol> + * + * @param array + * the given array + * @param start + * the given starting index + * @param end + * the given ending index + * @return a new array which is a copy of the given array starting at the + * given start and + * ending at the given end + * @exception NullPointerException + * if the given array is null + */ + public static final char[] subarray(char[] array, int start, int end) { + if (end == -1) + end = array.length; + if (start > end) + return null; + if (start < 0) + return null; + if (end > array.length) + return null; + char[] result = new char[end - start]; + System.arraycopy(array, start, result, 0, end - start); + return result; + } + + /** + * Answers the result of a char[] conversion to lowercase. Answers null if + * the given chars array is null. + * <br> + * NOTE: If no conversion was necessary, then answers back the argument one. + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * chars = { 'a' , 'b' } + * result => { 'a' , 'b' } + * </pre> + * </li> + * <li><pre> + * array = { 'A', 'b' } + * result => { 'a' , 'b' } + * </pre> + * </li> + * </ol> + * + * @param chars + * the chars to convert + * @return the result of a char[] conversion to lowercase + */ + final static public char[] toLowerCase(char[] chars) { + if (chars == null) + return null; + int length = chars.length; + char[] lowerChars = null; + for (int i = 0; i < length; i++) { + char c = chars[i]; + char lc = Character.toLowerCase(c); + if ((c != lc) || (lowerChars != null)) { + if (lowerChars == null) { + System.arraycopy(chars, 0, lowerChars = new char[length], + 0, i); + } + lowerChars[i] = lc; + } + } + return lowerChars == null ? chars : lowerChars; + } + + /** + * Answers a new array removing leading and trailing spaces (' '). Answers + * the given array if there is no + * space characters to remove. + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * chars = { ' ', 'a' , 'b', ' ', ' ' } + * result => { 'a' , 'b' } + * </pre> + * </li> + * <li><pre> + * array = { 'A', 'b' } + * result => { 'A' , 'b' } + * </pre> + * </li> + * </ol> + * + * @param chars + * the given array + * @return a new array removing leading and trailing spaces (' ') + */ + final static public char[] trim(char[] chars) { + if (chars == null) + return null; + int start = 0, length = chars.length, end = length - 1; + while (start < length && chars[start] == ' ') { + start++; + } + while (end > start && chars[end] == ' ') { + end--; + } + if (start != 0 || end != length - 1) { + return subarray(chars, start, end + 1); + } + return chars; + } + + /** + * Answers a string which is the concatenation of the given array using the + * '.' as a separator. + * <br> + * <br> + * For example: + * <ol> + * <li><pre> + * array = { { 'a' } , { 'b' } } + * result => "a.b" + * </pre> + * </li> + * <li><pre> + * array = { { ' ', 'a' } , { 'b' } } + * result => " a.b" + * </pre> + * </li> + * </ol> + * + * @param array + * the given array + * @return a string which is the concatenation of the given array using the + * '.' as a separator + */ + final static public String toString(char[][] array) { + char[] result = concatWith(array, '.'); + return new String(result); + } +} diff --git a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CheckersRegisry.java b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CheckersRegistry.java index 5661622..9a9dadc 100644 --- a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CheckersRegisry.java +++ b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CheckersRegistry.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009 Alena Laskavaia + * Copyright (c) 2009, 2010 Alena Laskavaia * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -17,36 +17,43 @@ import java.util.Iterator; import org.eclipse.cdt.codan.core.CodanCorePlugin; import org.eclipse.cdt.codan.core.PreferenceConstants; +import org.eclipse.cdt.codan.core.model.CodanSeverity; import org.eclipse.cdt.codan.core.model.IChecker; +import org.eclipse.cdt.codan.core.model.ICheckerWithPreferences; import org.eclipse.cdt.codan.core.model.ICheckersRegistry; import org.eclipse.cdt.codan.core.model.IProblem; import org.eclipse.cdt.codan.core.model.IProblemCategory; import org.eclipse.cdt.codan.core.model.IProblemProfile; +import org.eclipse.cdt.codan.core.model.IProblemWorkingCopy; import org.eclipse.cdt.codan.internal.core.model.CodanProblem; import org.eclipse.cdt.codan.internal.core.model.CodanProblemCategory; import org.eclipse.cdt.codan.internal.core.model.ProblemProfile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.ProjectScope; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.osgi.service.prefs.Preferences; -public class CheckersRegisry implements Iterable<IChecker>, ICheckersRegistry { - private static final String EXTENSION_POINT_NAME = "checkers"; - private static final String CHECKER_ELEMENT = "checker"; - private static final String PROBLEM_ELEMENT = "problem"; - private static final String CATEGORY_ELEMENT = "category"; - private static final Object DEFAULT = "DEFAULT"; +/** + * Implementation of checker registry interface + */ +public class CheckersRegistry implements Iterable<IChecker>, ICheckersRegistry { + private static final String NAME_ATTR = "name"; //$NON-NLS-1$ + private static final String ID_ATTR = "id"; //$NON-NLS-1$ + private static final String EXTENSION_POINT_NAME = "checkers"; //$NON-NLS-1$ + private static final String CHECKER_ELEMENT = "checker"; //$NON-NLS-1$ + private static final String PROBLEM_ELEMENT = "problem"; //$NON-NLS-1$ + private static final String CATEGORY_ELEMENT = "category"; //$NON-NLS-1$ + private static final Object DEFAULT = "DEFAULT"; //$NON-NLS-1$ private Collection<IChecker> checkers = new ArrayList<IChecker>(); - private static CheckersRegisry instance; + private static CheckersRegistry instance; private HashMap<Object, IProblemProfile> profiles = new HashMap<Object, IProblemProfile>(); private HashMap<IChecker, Collection<IProblem>> problemList = new HashMap<IChecker, Collection<IProblem>>(); - private CheckersRegisry() { + private CheckersRegistry() { instance = this; profiles.put(DEFAULT, new ProblemProfile()); readCheckersRegistry(); @@ -73,6 +80,27 @@ public class CheckersRegisry implements Iterable<IChecker>, ICheckersRegistry { IConfigurationElement configurationElement = elements[i]; processChecker(configurationElement); } + // init parameters for checkers with parameters + for (Iterator<IChecker> iterator = problemList.keySet().iterator(); iterator + .hasNext();) { + IChecker c = iterator.next(); + if (c instanceof ICheckerWithPreferences) { + Collection<IProblem> list = problemList.get(c); + for (Iterator<IProblem> iterator2 = list.iterator(); iterator2 + .hasNext();) { + IProblem p = iterator2.next(); + if (p instanceof IProblemWorkingCopy) { + try { + ((ICheckerWithPreferences) c) + .initPreferences((IProblemWorkingCopy) p); + } catch (Throwable t) { + t.printStackTrace(); + CodanCorePlugin.log(t); + } + } + } + } + } } /** @@ -80,15 +108,15 @@ public class CheckersRegisry implements Iterable<IChecker>, ICheckersRegistry { */ private void processCategories(IConfigurationElement configurationElement) { if (configurationElement.getName().equals(CATEGORY_ELEMENT)) { - String id = getAtt(configurationElement, "id"); + String id = getAtt(configurationElement, ID_ATTR); if (id == null) return; - String name = getAtt(configurationElement, "name"); + String name = getAtt(configurationElement, NAME_ATTR); if (name == null) return; CodanProblemCategory cat = new CodanProblemCategory(id, name); - String category = getAtt(configurationElement, "parentCategory", - false); + String category = getAtt(configurationElement, + "parentCategory", false); //$NON-NLS-1$ addCategory(cat, category); } } @@ -99,16 +127,16 @@ public class CheckersRegisry implements Iterable<IChecker>, ICheckersRegistry { private void processChecker(IConfigurationElement configurationElement) { try { if (configurationElement.getName().equals(CHECKER_ELEMENT)) { - String id = getAtt(configurationElement, "id"); + String id = getAtt(configurationElement, ID_ATTR); if (id == null) return; - String name = getAtt(configurationElement, "name", false); + String name = getAtt(configurationElement, NAME_ATTR, false); if (name == null) name = id; IChecker checkerObj = null; try { Object checker = configurationElement - .createExecutableExtension("class"); + .createExecutableExtension("class"); //$NON-NLS-1$ checkerObj = (IChecker) checker; addChecker(checkerObj); } catch (CoreException e) { @@ -116,7 +144,7 @@ public class CheckersRegisry implements Iterable<IChecker>, ICheckersRegistry { return; } IConfigurationElement[] children1 = configurationElement - .getChildren("problemRef"); + .getChildren("problemRef"); //$NON-NLS-1$ boolean hasRef = false; IConfigurationElement[] children2 = configurationElement .getChildren(PROBLEM_ELEMENT); @@ -131,7 +159,7 @@ public class CheckersRegisry implements Iterable<IChecker>, ICheckersRegistry { for (IConfigurationElement ref : children1) { hasRef = true; IProblem p = getDefaultProfile().findProblem( - ref.getAttribute("refId")); + ref.getAttribute("refId")); //$NON-NLS-1$ addRefProblem(checkerObj, p); } } @@ -141,7 +169,7 @@ public class CheckersRegisry implements Iterable<IChecker>, ICheckersRegistry { addRefProblem(checkerObj, p); } } - } catch (Exception e) { + } catch (Throwable e) { CodanCorePlugin.log(e); } } @@ -153,16 +181,37 @@ public class CheckersRegisry implements Iterable<IChecker>, ICheckersRegistry { private CodanProblem processProblem( IConfigurationElement configurationElement) { if (configurationElement.getName().equals(PROBLEM_ELEMENT)) { - String id = getAtt(configurationElement, "id"); + String id = getAtt(configurationElement, ID_ATTR); if (id == null) return null; - String name = getAtt(configurationElement, "name"); + String name = getAtt(configurationElement, NAME_ATTR); if (name == null) name = id; CodanProblem p = new CodanProblem(id, name); - String category = getAtt(configurationElement, "category", false); + String category = getAtt(configurationElement, "category", false); //$NON-NLS-1$ if (category == null) - category = "org.eclipse.cdt.codan.core.categories.ProgrammingProblems"; + category = "org.eclipse.cdt.codan.core.categories.ProgrammingProblems"; //$NON-NLS-1$ + String enab = getAtt(configurationElement, "defaultEnabled", false); //$NON-NLS-1$ + String sev = getAtt(configurationElement, "defaultSeverity", false); //$NON-NLS-1$ + String patt = getAtt(configurationElement, "messagePattern", false); //$NON-NLS-1$ + String desc = getAtt(configurationElement, "description", false); //$NON-NLS-1$ + String markerType = getAtt(configurationElement, + "markerType", false); //$NON-NLS-1$ + if (enab != null) { + p.setEnabled(Boolean.valueOf(enab)); + } + if (sev != null) { + CodanSeverity cSev = CodanSeverity.valueOf(sev); + if (cSev != null) + p.setSeverity(cSev); + } + if (patt != null) { + p.setMessagePattern(patt); + } + if (markerType != null) { + p.setMarkerType(markerType); + } + p.setDescription(desc); addProblem(p, category); return p; } @@ -178,11 +227,9 @@ public class CheckersRegisry implements Iterable<IChecker>, ICheckersRegistry { String name, boolean req) { String elementValue = configurationElement.getAttribute(name); if (elementValue == null && req) - CodanCorePlugin.log("Extension " - + configurationElement.getDeclaringExtension() - .getUniqueIdentifier() - + " missing required attribute: " - + configurationElement.getName() + "." + name); + CodanCorePlugin + .log("Extension " + configurationElement.getDeclaringExtension().getUniqueIdentifier() //$NON-NLS-1$ + + " missing required attribute: " + configurationElement.getName() + "." + name); //$NON-NLS-1$ //$NON-NLS-2$ return elementValue; } @@ -195,9 +242,9 @@ public class CheckersRegisry implements Iterable<IChecker>, ICheckersRegistry { return checkers.iterator(); } - public static CheckersRegisry getInstance() { + public static CheckersRegistry getInstance() { if (instance == null) - new CheckersRegisry(); + return new CheckersRegistry(); return instance; } @@ -256,9 +303,10 @@ public class CheckersRegisry implements Iterable<IChecker>, ICheckersRegistry { } plist.add(p); } - + /** * Returns list of problems registered for given checker + * * @return collection of problems or null */ public Collection<IProblem> getRefProblems(IChecker checker) { @@ -288,18 +336,21 @@ public class CheckersRegisry implements Iterable<IChecker>, ICheckersRegistry { wp = (IProblemProfile) getDefaultProfile().clone(); // load default values CodanPreferencesLoader loader = new CodanPreferencesLoader(wp); - loader.load(CodanCorePlugin.getDefault().getStorePreferences()); + loader.load(CodanPreferencesLoader.getWorkspaceNode()); } catch (CloneNotSupportedException e) { wp = getDefaultProfile(); } + profiles.put(ResourcesPlugin.getWorkspace(), wp); } return wp; } public void updateProfile(IResource element, IProblemProfile profile) { - if (profile == null) - profiles.remove(element); - else + // updating profile can invalidate all cached profiles + IProblemProfile defaultProfile = getDefaultProfile(); + profiles.clear(); + profiles.put(DEFAULT, defaultProfile); + if (profile != null && element != null) profiles.put(element, profile); } @@ -319,15 +370,14 @@ public class CheckersRegisry implements Iterable<IChecker>, ICheckersRegistry { // load default values CodanPreferencesLoader loader = new CodanPreferencesLoader( prof); - IEclipsePreferences node = new ProjectScope( - (IProject) element) - .getNode(CodanCorePlugin.PLUGIN_ID); - boolean useWorkspace = node.getBoolean( + Preferences projectNode = CodanPreferencesLoader + .getProjectNode((IProject) element); + boolean useWorkspace = projectNode.getBoolean( PreferenceConstants.P_USE_PARENT, false); if (!useWorkspace) { - loader.load(node); + loader.load(projectNode); } - updateProfile(element, prof); + profiles.put(element, prof); } catch (CloneNotSupportedException e) { // cant } @@ -348,20 +398,45 @@ public class CheckersRegisry implements Iterable<IChecker>, ICheckersRegistry { * getResourceProfileWorkingCopy(org.eclipse.core.resources.IResource) */ public IProblemProfile getResourceProfileWorkingCopy(IResource element) { - if (element instanceof IProject) { - try { - IProblemProfile prof = (IProblemProfile) getWorkspaceProfile() - .clone(); - // load default values - CodanPreferencesLoader loader = new CodanPreferencesLoader(prof); - IEclipsePreferences node = new ProjectScope((IProject) element) - .getNode(CodanCorePlugin.PLUGIN_ID); - loader.load(node); - return prof; - } catch (CloneNotSupportedException e) { - // cant - } + try { + IProblemProfile prof = (IProblemProfile) getResourceProfile(element) + .clone(); + return prof; + } catch (CloneNotSupportedException e) { + // cant + return null; } - return null; + } + + /** + * Test if checker is enabled (needs to be run) or not. Checker is enabled + * if at least one problem it prints is enabled. + * + * @param checker + * @param resource + * @return + */ + public boolean isCheckerEnabled(IChecker checker, IResource resource) { + IProblemProfile resourceProfile = getResourceProfile(resource); + Collection<IProblem> refProblems = getRefProblems(checker); + for (Iterator<IProblem> iterator = refProblems.iterator(); iterator + .hasNext();) { + IProblem p = iterator.next(); + // we need to check problem enablement in particular profile + IProblem problem = resourceProfile.findProblem(p.getId()); + if (problem == null) + throw new IllegalArgumentException("Id is not registered"); //$NON-NLS-1$ + if (problem.isEnabled()) + return true; + } + // no problem is enabled for this checker, skip the checker + return false; + } + + /** + * @return + */ + public int getCheckersSize() { + return checkers.size(); } } diff --git a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CodanApplication.java b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CodanApplication.java new file mode 100644 index 0000000..188be3c --- /dev/null +++ b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CodanApplication.java @@ -0,0 +1,118 @@ +/******************************************************************************* + * Copyright (c) 2010 Alena Laskavaia and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alena Laskavaia - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.internal.core; + +import java.util.ArrayList; +import java.util.Collection; + +import org.eclipse.cdt.codan.core.CodanRuntime; +import org.eclipse.cdt.codan.core.Messages; +import org.eclipse.cdt.codan.internal.core.model.CodanMarkerProblemReporter; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.equinox.app.IApplication; +import org.eclipse.equinox.app.IApplicationContext; +import org.eclipse.osgi.util.NLS; + +/** + * Application to support headless build + * + * @noextend This class is not intended to be extended by clients. + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class CodanApplication implements IApplication { + private Collection<String> projects = new ArrayList<String>(); + private boolean verbose = false; + private boolean all = false; + + public Object start(IApplicationContext context) throws Exception { + String[] args = (String[]) context.getArguments().get( + "application.args"); //$NON-NLS-1$ + if (args == null || args.length == 0) { + help(); + return EXIT_OK; + } + extractArguments(args); + CodanBuilder codanBuilder = new CodanBuilder(); + CodanRuntime runtime = CodanRuntime.getInstance(); + runtime.setProblemReporter(new CodanMarkerProblemReporter() { + @Override + public void reportProblem(String id, String markerType, + int severity, IResource file, int lineNumber, + int startChar, int endChar, String message) { + System.out.println(file.getLocation() + ":" + lineNumber + ": " //$NON-NLS-1$ //$NON-NLS-2$ + + message); + } + }); + IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); + if (all) { + log(Messages.CodanApplication_LogRunWorkspace); + codanBuilder.processResource(root, new NullProgressMonitor()); + } else { + for (String project : projects) { + log(Messages.CodanApplication_LogRunProject + project); + IProject wProject = root.getProject(project); + if (!wProject.exists()) { + System.err + .println( // + NLS.bind( + Messages.CodanApplication_Error_ProjectDoesNotExists, + project)); + continue; + } + codanBuilder.processResource(wProject, + new NullProgressMonitor()); + } + } + return EXIT_OK; + } + + /** + * @param string + */ + private void log(String string) { + if (verbose) + System.err.println(string); + } + + /** + * @param args + */ + private void extractArguments(String[] args) { + for (int i = 0; i < args.length; i++) { + String string = args[i]; + if (string.equals("-verbose")) { //$NON-NLS-1$ + verbose = true; + } else if (string.equals("-all")) { //$NON-NLS-1$ + all = true; + } else { + projects.add(string); + } + } + } + + /** + * + */ + private void help() { + System.out.println(Messages.CodanApplication_Usage); + System.out.println(Messages.CodanApplication_Options); + System.out.println(Messages.CodanApplication_all_option); + System.out.println(Messages.CodanApplication_verbose_option); + } + + public void stop() { + // nothing + } +} diff --git a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CodanBuilder.java b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CodanBuilder.java index 56916b8..6685b98 100644 --- a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CodanBuilder.java +++ b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CodanBuilder.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009 Alena Laskavaia + * Copyright (c) 2009, 2010 Alena Laskavaia * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -10,91 +10,74 @@ *******************************************************************************/ package org.eclipse.cdt.codan.internal.core; -import java.io.File; -import java.net.URI; -import java.util.Collection; -import java.util.Iterator; import java.util.Map; import org.eclipse.cdt.codan.core.CodanCorePlugin; import org.eclipse.cdt.codan.core.CodanRuntime; -import org.eclipse.cdt.codan.core.model.ICAstChecker; +import org.eclipse.cdt.codan.core.Messages; import org.eclipse.cdt.codan.core.model.IChecker; -import org.eclipse.cdt.codan.core.model.ICodanAstReconciler; import org.eclipse.cdt.codan.core.model.ICodanBuilder; -import org.eclipse.cdt.codan.core.model.IProblem; -import org.eclipse.cdt.codan.core.model.IProblemProfile; import org.eclipse.cdt.codan.core.model.IProblemReporter; -import org.eclipse.cdt.codan.internal.core.model.CodanMarkerProblemReporter; -import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; -import org.eclipse.core.resources.IFile; +import org.eclipse.cdt.codan.core.model.IProblemReporterPersistent; +import org.eclipse.cdt.codan.core.model.IRunnableInEditorChecker; +import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.resources.IResourceDeltaVisitor; -import org.eclipse.core.resources.IResourceVisitor; -import org.eclipse.core.resources.IWorkspace; -import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.IncrementalProjectBuilder; -import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.SubProgressMonitor; +/** + * Implementation of {@link ICodanBuilder} + */ public class CodanBuilder extends IncrementalProjectBuilder implements - ICodanBuilder, ICodanAstReconciler { - public static final String BUILDER_ID = "org.eclipse.cdt.codan.core.codanBuilder"; + ICodanBuilder { + /** + * codan builder id + */ + public static final String BUILDER_ID = "org.eclipse.cdt.codan.core.codanBuilder"; //$NON-NLS-1$ - public class CodanDeltaVisitor implements IResourceDeltaVisitor { - /* - * (non-Javadoc) - * - * @see - * org.eclipse.core.resources.IResourceDeltaVisitor#visit(org.eclipse - * .core.resources.IResourceDelta) - */ - /* - * (non-Javadoc) - * - * @see - * org.eclipse.cdt.codan.internal.core.ICodanBuilder#visit(org.eclipse - * .core.resources.IResourceDelta) + private class CodanDeltaVisitor implements IResourceDeltaVisitor { + private IProgressMonitor monitor; + + /** + * @param monitor */ + public CodanDeltaVisitor(IProgressMonitor monitor) { + this.monitor = monitor; + } + public boolean visit(IResourceDelta delta) throws CoreException { IResource resource = delta.getResource(); switch (delta.getKind()) { - case IResourceDelta.ADDED: - // handle added resource - processResource(resource, new NullProgressMonitor()); - break; - case IResourceDelta.REMOVED: - // handle removed resource - break; - case IResourceDelta.CHANGED: - // handle changed resource - processResource(resource, new NullProgressMonitor()); - break; + case IResourceDelta.ADDED: + // handle added resource + processResource(resource, monitor); + break; + case IResourceDelta.REMOVED: + // handle removed resource + break; + case IResourceDelta.CHANGED: + // handle changed resource + processResource(resource, monitor); + break; } // return true to continue visiting children. return true; } } - public class CodanResourceVisitor implements IResourceVisitor { - public boolean visit(IResource resource) { - if (!(resource instanceof IProject)) - processResource(resource, new NullProgressMonitor()); - // return true to continue visiting children. - return true; - } - } - /* * (non-Javadoc) * * @see org.eclipse.core.internal.events.InternalBuilder#build(int, * java.util.Map, org.eclipse.core.runtime.IProgressMonitor) */ + @SuppressWarnings("rawtypes") + @Override protected IProject[] build(int kind, Map args, IProgressMonitor monitor) throws CoreException { if (kind == FULL_BUILD) { @@ -111,119 +94,101 @@ public class CodanBuilder extends IncrementalProjectBuilder implements } public void processResource(IResource resource, IProgressMonitor monitor) { - // String string = Platform.getPreferencesService().getString( - // CodanCorePlugin.PLUGIN_ID, "problems", "", null); - // System.err.println("set = " + string); - // delete general markers - IProblemReporter problemReporter = CodanRuntime.getInstance() - .getProblemReporter(); - if (problemReporter instanceof CodanMarkerProblemReporter) { - ((CodanMarkerProblemReporter) problemReporter) - .deleteMarkers(resource); - } - for (IChecker checker : CheckersRegisry.getInstance()) { - try { - boolean run = false; - if (checker.enabledInContext(resource)) - run = true; - if (areProblemsForCheckerEnabled(checker, resource)) - run = true; - if (run) - checker.processResource(resource); - } catch (Throwable e) { - CodanCorePlugin.log(e); - } - } - if (resource instanceof IProject) { + processResource(resource, monitor, null, false); + } + + protected void processResource(IResource resource, + IProgressMonitor monitor, Object model, boolean inEditor) { + CheckersRegistry chegistry = CheckersRegistry.getInstance(); + int checkers = chegistry.getCheckersSize(); + int memsize = 0; + if (resource instanceof IContainer) { try { - resource.accept(getResourceVisitor()); + IResource[] members = ((IContainer) resource).members(); + memsize = members.length; } catch (CoreException e) { CodanCorePlugin.log(e); } } - } - - public void reconcileAst(IASTTranslationUnit ast, IProgressMonitor monitor) { - if (ast == null) - return; - String filePath = ast.getFilePath(); - IWorkspace workspace = ResourcesPlugin.getWorkspace(); - IWorkspaceRoot root = workspace.getRoot(); - IFile[] resources; - URI uri = new File(filePath).toURI(); - resources = root.findFilesForLocationURI(uri); - if (resources != null && resources.length > 0) { - IFile resource = resources[0]; + int tick = 1000; + // System.err.println("processing " + resource); + monitor.beginTask(Messages.CodanBuilder_Code_Analysis_On + resource, + checkers + memsize * tick); + try { IProblemReporter problemReporter = CodanRuntime.getInstance() .getProblemReporter(); - // TODO: this is wrong - should not delete all markers - - // only those that contributed by the checker that we run now - if (problemReporter instanceof CodanMarkerProblemReporter) { - ((CodanMarkerProblemReporter) problemReporter) - .deleteMarkers(resource); - } - for (IChecker checker : CheckersRegisry.getInstance()) { + for (IChecker checker : chegistry) { try { - boolean run = false; - if (checker.enabledInContext(resource)) - run = true; - if (areProblemsForCheckerEnabled(checker, resource)) { - run = true; + if (monitor.isCanceled()) + return; + if (checker.enabledInContext(resource)) { + // delete markers if checker can possibly run on this + // resource + // this way if checker is not enabled markers would be + // deleted too + if (problemReporter instanceof IProblemReporterPersistent) { + // delete general markers + ((IProblemReporterPersistent) problemReporter) + .deleteProblems(resource, checker); + } + if (chegistry.isCheckerEnabled(checker, resource)) { + if (inEditor) { + if (checker.runInEditor() + && checker instanceof IRunnableInEditorChecker) { + ((IRunnableInEditorChecker) checker) + .processModel(model); + } + } else { + checker.processResource(resource); + } + } } - if (run && checker instanceof ICAstChecker - && checker.runInEditor()) - ((ICAstChecker) checker).processAst(ast); + monitor.worked(1); } catch (Throwable e) { CodanCorePlugin.log(e); } } + if (resource instanceof IContainer) { + try { + IResource[] members = ((IContainer) resource).members(); + for (int i = 0; i < members.length; i++) { + if (monitor.isCanceled()) + return; + IResource member = members[i]; + processResource(member, new SubProgressMonitor(monitor, + tick)); + } + } catch (CoreException e) { + CodanCorePlugin.log(e); + } + } + } finally { + monitor.done(); } } - /** - * @param checker - * @param resource - * @return - */ - private boolean areProblemsForCheckerEnabled(IChecker checker, - IResource resource) { - IProblemProfile resourceProfile = CheckersRegisry.getInstance() - .getResourceProfile(resource); - Collection<IProblem> refProblems = CheckersRegisry.getInstance() - .getRefProblems(checker); - for (Iterator iterator = refProblems.iterator(); iterator.hasNext();) { - IProblem p = (IProblem) iterator.next(); - // we need to check problem enablement in particular profile - IProblem problem = resourceProfile.findProblem(p.getId()); - if (problem == null) - throw new IllegalArgumentException("Id is not registered"); - if (problem.isEnabled()) - return true; - } - // no problem is enabled for this checker, skip the checker - return false; - } - protected void fullBuild(final IProgressMonitor monitor) throws CoreException { - try { - getProject().accept(new CodanResourceVisitor()); - } catch (CoreException e) { - } + processResource(getProject(), monitor); } protected void incrementalBuild(IResourceDelta delta, IProgressMonitor monitor) throws CoreException { // the visitor does the work. - delta.accept(new CodanDeltaVisitor()); + delta.accept(new CodanDeltaVisitor(monitor)); } - /* - * (non-Javadoc) + /** + * Run all checkers that support "check as you type" mode * - * @see org.eclipse.cdt.codan.core.model.ICodanBuilder#getResourceVisitor() + * @param model - model of given resource such as ast + * @param resource - resource to process + * @param monitor - progress monitor */ - public CodanResourceVisitor getResourceVisitor() { - return new CodanResourceVisitor(); + public void runInEditor(Object model, IResource resource, + IProgressMonitor monitor) { + if (model == null) + return; + processResource(resource, monitor, model, true); } } diff --git a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CodanPreferencesLoader.java b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CodanPreferencesLoader.java index bafff9a..38af027 100644 --- a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CodanPreferencesLoader.java +++ b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CodanPreferencesLoader.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009 Alena Laskavaia + * Copyright (c) 2009, 2010 Alena Laskavaia * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -10,38 +10,50 @@ *******************************************************************************/ package org.eclipse.cdt.codan.internal.core; +import org.eclipse.cdt.codan.core.CodanCorePlugin; import org.eclipse.cdt.codan.core.model.CodanSeverity; import org.eclipse.cdt.codan.core.model.IProblem; import org.eclipse.cdt.codan.core.model.IProblemProfile; -import org.eclipse.cdt.codan.internal.core.model.CodanProblem; -import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.eclipse.cdt.codan.core.model.IProblemWorkingCopy; +import org.eclipse.cdt.codan.core.param.IProblemPreference; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.ProjectScope; +import org.eclipse.core.runtime.preferences.InstanceScope; +import org.osgi.service.prefs.Preferences; /** - * @author Alena + * Helper class to load/save problem profile settings in persistent storage * */ public class CodanPreferencesLoader { private IProblemProfile baseModel; /** - * @param workspaceProfile + * Constructor + * + * @param profile - problem profile to work with */ public CodanPreferencesLoader(IProblemProfile profile) { setInput(profile); } /** - * + * Default constructor */ public CodanPreferencesLoader() { } - public void setInput(Object model) { - baseModel = (IProblemProfile) model; + /** + * Sets the profile for this class + * + * @param profile + */ + public void setInput(IProblemProfile profile) { + baseModel = profile; } /** - * @return + * @return problems array from the profile */ public IProblem[] getProblems() { IProblem[] problems = baseModel.getProblems(); @@ -54,66 +66,144 @@ public class CodanPreferencesLoader { */ public void setProperty(String id, String s) { IProblem prob = baseModel.findProblem(id); - if (!(prob instanceof CodanProblem)) + if (!(prob instanceof IProblemWorkingCopy)) return; String sevs = s; boolean enabled = true; - if (sevs.startsWith("-")) { + if (sevs.startsWith("-")) { //$NON-NLS-1$ sevs = sevs.substring(1); enabled = false; } - ((CodanProblem) prob).setEnabled(enabled); + ((IProblemWorkingCopy) prob).setEnabled(enabled); CodanSeverity sev; try { sev = CodanSeverity.valueOf(sevs); } catch (RuntimeException e) { sev = CodanSeverity.Warning; } - ((CodanProblem) prob).setSeverity(sev); + ((IProblemWorkingCopy) prob).setSeverity(sev); } - /* - * (non-Javadoc) - * - * @see java.lang.Object#toString() - */ @Override public String toString() { return getInput().toString(); } /** - * @return + * @return problem profile set for this class */ public IProblemProfile getInput() { return baseModel; } /** - * @param id - * @return + * @param id - property id, which is the same as problem id + * @return get text representation of a "property" value for the given id, + * which is severity name, with "-" in front of it it problem is + * disabled. */ public String getProperty(String id) { IProblem prob = baseModel.findProblem(id); - if (!(prob instanceof CodanProblem)) - return null; - String enabled = prob.isEnabled() ? "" : "-"; + String enabled = prob.isEnabled() ? "" : "-"; //$NON-NLS-1$ //$NON-NLS-2$ String severity = prob.getSeverity().toString(); String res = enabled + severity; return res; } /** + * Takes string values from storePreferences and applies them to the problem + * profile + * * @param storePreferences */ - public void load(IEclipsePreferences storePreferences) { + public void load(Preferences storePreferences) { IProblem[] probs = getProblems(); for (int i = 0; i < probs.length; i++) { String id = probs[i].getId(); String s = storePreferences.get(id, null); if (s != null) { setProperty(id, s); + setProblemPreferenceValues(id, storePreferences); } } } + + /** + * Takes string values of the problem preferences from storePreferences + * and applies them to the problem profile + * + * @param problemId + * @param storePreferences + */ + private void setProblemPreferenceValues(String problemId, + Preferences storePreferences) { + IProblem prob = baseModel.findProblem(problemId); + String prefKey = getPreferencesKey(problemId); + if (prefKey == null) + return; + String exported = storePreferences.get(prefKey, null); + if (exported != null) { + //System.err.println(prefKey + " import " + exported); + prob.getPreference().importValue(exported); + } + } + + /** + * Return preference node (osgi preferences) for the project + * + * @param project + * @return project preferences node + */ + public static Preferences getProjectNode(IProject project) { + if (!project.exists()) + return null; + Preferences prefNode = new ProjectScope(project) + .getNode(CodanCorePlugin.PLUGIN_ID); + if (prefNode == null) + return null; + return prefNode; + } + + /** + * Return preference node (osgi preferences) for the workspace + * + * @return project preferences node + */ + public static Preferences getWorkspaceNode() { + Preferences prefNode = new InstanceScope() + .getNode(CodanCorePlugin.PLUGIN_ID); + if (prefNode == null) + return null; + return prefNode; + } + + /** + * Name of the preference key for the root problem preference in the osgi + * preferences + * + * @param id - problem id + * @return top level preference id + */ + public String getPreferencesKey(String id) { + IProblem prob = baseModel.findProblem(id); + IProblemPreference pref = prob.getPreference(); + if (pref == null) + return null; + return id + "." + pref.getKey(); //$NON-NLS-1$ + } + + /** + * @param id - problem id + * @return - export value of root problem preference (to be saved in eclipse + * preferences) + */ + public String getPreferencesString(String id) { + IProblem prob = baseModel.findProblem(id); + IProblemPreference pref = prob.getPreference(); + if (pref == null) + return null; + String str = pref.exportValue(); + //System.err.println(id + " set " + str); + return str; + } } diff --git a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CodeAnlysisNature.java b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CodeAnlysisNature.java index 5157e16..f73ee61 100644 --- a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CodeAnlysisNature.java +++ b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CodeAnlysisNature.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009 Alena Laskavaia + * Copyright (c) 2009, 2010 Alena Laskavaia * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -16,18 +16,16 @@ import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.resources.IProjectNature; import org.eclipse.core.runtime.CoreException; +/** + * Code Analysis Nature for builder + */ public class CodeAnlysisNature implements IProjectNature { /** * ID of this project nature */ - public static final String NATURE_ID = "org.eclipse.cdt.codan.core.codanNature"; + public static final String NATURE_ID = "org.eclipse.cdt.codan.core.codanNature"; //$NON-NLS-1$ private IProject project; - /* - * (non-Javadoc) - * - * @see org.eclipse.core.resources.IProjectNature#configure() - */ public void configure() throws CoreException { IProjectDescription desc = project.getDescription(); ICommand[] commands = desc.getBuildSpec(); @@ -45,11 +43,6 @@ public class CodeAnlysisNature implements IProjectNature { project.setDescription(desc, null); } - /* - * (non-Javadoc) - * - * @see org.eclipse.core.resources.IProjectNature#deconfigure() - */ public void deconfigure() throws CoreException { IProjectDescription description = getProject().getDescription(); ICommand[] commands = description.getBuildSpec(); @@ -66,22 +59,10 @@ public class CodeAnlysisNature implements IProjectNature { } } - /* - * (non-Javadoc) - * - * @see org.eclipse.core.resources.IProjectNature#getProject() - */ public IProject getProject() { return project; } - /* - * (non-Javadoc) - * - * @see - * org.eclipse.core.resources.IProjectNature#setProject(org.eclipse.core - * .resources.IProject) - */ public void setProject(IProject project) { this.project = project; } diff --git a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/AbstractBasicBlock.java b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/AbstractBasicBlock.java new file mode 100644 index 0000000..15a191a --- /dev/null +++ b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/AbstractBasicBlock.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2010 Alena Laskavaia and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alena Laskavaia - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.internal.core.cfg; + +import org.eclipse.cdt.codan.core.model.cfg.IBasicBlock; +import org.eclipse.cdt.codan.core.model.cfg.ICfgData; + +/** + * Abstract Basic Block for control flow graph. + */ +public abstract class AbstractBasicBlock implements IBasicBlock, ICfgData { + /** + * Empty array of basic blocks + */ + public final static IBasicBlock[] EMPTY_LIST = new IBasicBlock[0]; + private Object data; + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } + + /** + * Add a node to list of outgoing nodes of this node + * + * @param node - node to add + */ + public abstract void addOutgoing(IBasicBlock node); + + /** + * Add a node to list of incoming nodes of this node + * + * @param node - node to add + */ + public abstract void addIncoming(IBasicBlock node); + + /** + * @return toString for data object + */ + public String toStringData() { + if (getData() == null) + return "0x" + Integer.toHexString(System.identityHashCode(this)); //$NON-NLS-1$ + return getData().toString(); + } + + @Override + public String toString() { + return getClass().getSimpleName() + ": " + toStringData(); //$NON-NLS-1$ + } +} diff --git a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/AbstractSingleIncomingNode.java b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/AbstractSingleIncomingNode.java new file mode 100644 index 0000000..9054f2a --- /dev/null +++ b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/AbstractSingleIncomingNode.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2010 Alena Laskavaia and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alena Laskavaia - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.internal.core.cfg; + +import org.eclipse.cdt.codan.core.model.cfg.IBasicBlock; +import org.eclipse.cdt.codan.core.model.cfg.ISingleIncoming; + +/** + * Abstract node with one incoming arc (node) + * + */ +public abstract class AbstractSingleIncomingNode extends AbstractBasicBlock + implements ISingleIncoming { + private IBasicBlock prev; + + /** + * Default constructor + */ + public AbstractSingleIncomingNode() { + super(); + } + + public IBasicBlock[] getIncomingNodes() { + return new IBasicBlock[] { prev }; + } + + public int getIncomingSize() { + return 1; + } + + public IBasicBlock getIncoming() { + return prev; + } + + /** + * Sets the incoming node + * + * @param prev + */ + public void setIncoming(IBasicBlock prev) { + this.prev = prev; + } + + @Override + public void addIncoming(IBasicBlock node) { + setIncoming(node); + } +} diff --git a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/AbstractSingleOutgoingNode.java b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/AbstractSingleOutgoingNode.java new file mode 100644 index 0000000..e4f7fcf --- /dev/null +++ b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/AbstractSingleOutgoingNode.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2010 Alena Laskavaia and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alena Laskavaia - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.internal.core.cfg; + +import org.eclipse.cdt.codan.core.model.cfg.IBasicBlock; +import org.eclipse.cdt.codan.core.model.cfg.ISingleOutgoing; + +/** + * Abstract implementation of basic block with single outgoing arc (node) + * + */ +public abstract class AbstractSingleOutgoingNode extends AbstractBasicBlock + implements ISingleOutgoing { + private IBasicBlock next; + + /** + * Default constructor + */ + public AbstractSingleOutgoingNode() { + super(); + } + + public IBasicBlock[] getOutgoingNodes() { + return new IBasicBlock[] { next }; + } + + public int getOutgoingSize() { + return 1; + } + + public IBasicBlock getOutgoing() { + return next; + } + + /** + * Sets outgoing node + * + * @param node + */ + public void setOutgoing(IBasicBlock node) { + this.next = node; + } + + @Override + public void addOutgoing(IBasicBlock node) { + setOutgoing(node); + } +} diff --git a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/BranchNode.java b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/BranchNode.java new file mode 100644 index 0000000..ecd99e1 --- /dev/null +++ b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/BranchNode.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 Alena Laskavaia + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alena Laskavaia - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.internal.core.cfg; + +import org.eclipse.cdt.codan.core.model.cfg.IBranchNode; + +/** + * Branch node is a node with on incoming arc, one outgoing arc and a "string" + * label. Can be used to represent branches of if, switch and labelled + * statements. + */ +public class BranchNode extends PlainNode implements IBranchNode { + protected String label; + + protected BranchNode(String label) { + super(); + this.label = label; + } + + public String getLabel() { + return label; + } + + @Override + public String toStringData() { + return label; + } +} diff --git a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/CVS/Entries b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/CVS/Entries new file mode 100644 index 0000000..bd763ef --- /dev/null +++ b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/CVS/Entries @@ -0,0 +1,12 @@ +/AbstractBasicBlock.java/1.10/Thu Jun 3 17:01:52 2010//TCDT_7_0_0 +/AbstractSingleIncomingNode.java/1.6/Thu Jun 3 17:01:52 2010//TCDT_7_0_0 +/AbstractSingleOutgoingNode.java/1.6/Thu Jun 3 17:01:52 2010//TCDT_7_0_0 +/BranchNode.java/1.5/Thu Jun 3 17:01:52 2010//TCDT_7_0_0 +/ConnectorNode.java/1.7/Thu Jun 3 17:01:52 2010//TCDT_7_0_0 +/ControlFlowGraph.java/1.11/Thu Jun 3 17:01:52 2010//TCDT_7_0_0 +/DecisionNode.java/1.9/Thu Jun 3 17:01:52 2010//TCDT_7_0_0 +/ExitNode.java/1.6/Thu Jun 3 17:01:52 2010//TCDT_7_0_0 +/JumpNode.java/1.9/Thu Jun 3 17:01:52 2010//TCDT_7_0_0 +/NodeFactory.java/1.2/Thu Jun 3 17:01:52 2010//TCDT_7_0_0 +/PlainNode.java/1.8/Thu Jun 3 17:01:52 2010//TCDT_7_0_0 +/StartNode.java/1.8/Thu Jun 3 17:01:52 2010//TCDT_7_0_0 diff --git a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/CVS/Repository b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/CVS/Repository new file mode 100644 index 0000000..34bede2 --- /dev/null +++ b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/CVS/Repository @@ -0,0 +1 @@ +org.eclipse.cdt/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg diff --git a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/CVS/Root b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/CVS/Root new file mode 100644 index 0000000..04efa23 --- /dev/null +++ b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/CVS/Root @@ -0,0 +1 @@ +:pserver:anonymous@dev.eclipse.org:/cvsroot/tools diff --git a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/CVS/Tag b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/CVS/Tag new file mode 100644 index 0000000..49a449a --- /dev/null +++ b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/CVS/Tag @@ -0,0 +1 @@ +NCDT_7_0_0 diff --git a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/ConnectorNode.java b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/ConnectorNode.java new file mode 100644 index 0000000..7c91818 --- /dev/null +++ b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/ConnectorNode.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 Alena Laskavaia + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alena Laskavaia - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.internal.core.cfg; + +import java.util.ArrayList; + +import org.eclipse.cdt.codan.core.model.cfg.IBasicBlock; +import org.eclipse.cdt.codan.core.model.cfg.IConnectorNode; +import org.eclipse.cdt.codan.core.model.cfg.IJumpNode; + +/** + * TODO: add description + */ +public class ConnectorNode extends AbstractSingleOutgoingNode implements + IConnectorNode { + protected ArrayList<IBasicBlock> incoming = new ArrayList<IBasicBlock>(2); + + protected ConnectorNode() { + super(); + } + + @Override + public void addIncoming(IBasicBlock node) { + incoming.add(node); + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.cdt.codan.provisional.core.model.cfg.IBasicBlock# + * getIncomingIterator() + */ + public IBasicBlock[] getIncomingNodes() { + return incoming.toArray(new IBasicBlock[incoming.size()]); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.cdt.codan.core.model.cfg.IBasicBlock#getIncomingSize () + */ + public int getIncomingSize() { + return incoming.size(); + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.cdt.codan.provisional.core.model.cfg.IConnectorNode# + * hasBackwardIncoming() + */ + public boolean hasBackwardIncoming() { + for (IBasicBlock node : incoming) { + if (node instanceof IJumpNode) { + if (((IJumpNode) node).isBackwardArc()) + return true; + } + } + return false; + } +} diff --git a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/ControlFlowGraph.java b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/ControlFlowGraph.java new file mode 100644 index 0000000..8133e8c --- /dev/null +++ b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/ControlFlowGraph.java @@ -0,0 +1,147 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 Alena Laskavaia + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alena Laskavaia - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.internal.core.cfg; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; + +import org.eclipse.cdt.codan.core.model.cfg.IBasicBlock; +import org.eclipse.cdt.codan.core.model.cfg.IBranchNode; +import org.eclipse.cdt.codan.core.model.cfg.IConnectorNode; +import org.eclipse.cdt.codan.core.model.cfg.IControlFlowGraph; +import org.eclipse.cdt.codan.core.model.cfg.IDecisionNode; +import org.eclipse.cdt.codan.core.model.cfg.IExitNode; +import org.eclipse.cdt.codan.core.model.cfg.ISingleOutgoing; +import org.eclipse.cdt.codan.core.model.cfg.IStartNode; + +/** + * Implementation of control flow graph + */ +public class ControlFlowGraph implements IControlFlowGraph { + private List<IExitNode> exitNodes; + private List<IBasicBlock> deadNodes = new ArrayList<IBasicBlock>(); + private IStartNode start; + + public ControlFlowGraph(IStartNode start, Collection<IExitNode> exitNodes) { + setExitNodes(exitNodes); + this.start = start; + } + + public Iterator<IExitNode> getExitNodeIterator() { + return exitNodes.iterator(); + } + + public int getExitNodeSize() { + return exitNodes.size(); + } + + public void setExitNodes(Collection<IExitNode> exitNodes) { + if (this.exitNodes != null) + throw new IllegalArgumentException( + "Cannot modify already exiting connector"); //$NON-NLS-1$ + this.exitNodes = Collections.unmodifiableList(new ArrayList<IExitNode>( + exitNodes)); + } + + public void setUnconnectedNodes(Collection<IBasicBlock> nodes) { + this.deadNodes = Collections + .unmodifiableList(new ArrayList<IBasicBlock>(nodes)); + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.cdt.codan.provisional.core.model.cfg.IControlFlowGraph# + * getStartNode() + */ + public IStartNode getStartNode() { + return start; + } + + void setStartNode(IStartNode start) { + this.start = start; + } + + public void print(IBasicBlock node) { + System.out.println(node.getClass().getSimpleName() + ": " //$NON-NLS-1$ + + ((AbstractBasicBlock) node).toStringData()); + if (node instanceof IDecisionNode) { + // todo + IBasicBlock[] branches = ((IDecisionNode) node).getOutgoingNodes(); + for (int i = 0; i < branches.length; i++) { + IBasicBlock brNode = branches[i]; + System.out.println("{"); //$NON-NLS-1$ + print(brNode); + System.out.println("}"); //$NON-NLS-1$ + } + print(((IDecisionNode) node).getMergeNode()); + } else if (node instanceof ISingleOutgoing) { + IBasicBlock next = ((ISingleOutgoing) node).getOutgoing(); + if (!(next instanceof IConnectorNode && !(next instanceof IBranchNode))) + print(next); + } + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.cdt.codan.provisional.core.model.cfg.IControlFlowGraph# + * getUnconnectedNodeIterator() + */ + public Iterator<IBasicBlock> getUnconnectedNodeIterator() { + return deadNodes.iterator(); + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.cdt.codan.provisional.core.model.cfg.IControlFlowGraph# + * getUnconnectedNodeSize() + */ + public int getUnconnectedNodeSize() { + return deadNodes.size(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.cdt.codan.core.model.cfg.IControlFlowGraph#getNodes () + */ + public Collection<IBasicBlock> getNodes() { + Collection<IBasicBlock> result = new LinkedHashSet<IBasicBlock>(); + getNodes(getStartNode(), result); + for (Iterator<IBasicBlock> iterator = deadNodes.iterator(); iterator + .hasNext();) { + IBasicBlock d = iterator.next(); + getNodes(d, result); + } + return result; + } + + /** + * @param d + * @param result + */ + private void getNodes(IBasicBlock start, Collection<IBasicBlock> result) { + if (result.contains(start)) + return; + result.add(start); + IBasicBlock[] outgoingNodes = start.getOutgoingNodes(); + for (int i = 0; i < outgoingNodes.length; i++) { + IBasicBlock b = outgoingNodes[i]; + getNodes(b, result); + } + } +} diff --git a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/DecisionNode.java b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/DecisionNode.java new file mode 100644 index 0000000..df0da9c --- /dev/null +++ b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/DecisionNode.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 Alena Laskavaia + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alena Laskavaia - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.internal.core.cfg; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.cdt.codan.core.model.cfg.IBasicBlock; +import org.eclipse.cdt.codan.core.model.cfg.IBranchNode; +import org.eclipse.cdt.codan.core.model.cfg.IConnectorNode; +import org.eclipse.cdt.codan.core.model.cfg.IDecisionNode; + +/** + * @see {@link IDecisionNode} + */ +public class DecisionNode extends AbstractSingleIncomingNode implements + IDecisionNode { + private List<IBasicBlock> next = new ArrayList<IBasicBlock>(2); + private IConnectorNode conn; + + /** + * @param prev + */ + protected DecisionNode() { + super(); + } + + @Override + public void addOutgoing(IBasicBlock node) { + IBranchNode cnode = (IBranchNode) node; // cast to throw CCE + next.add(cnode); + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.cdt.codan.provisional.core.model.cfg.IBasicBlock# + * getOutgoingIterator() + */ + public IBasicBlock[] getOutgoingNodes() { + return next.toArray(new IBasicBlock[next.size()]); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.cdt.codan.core.model.cfg.IBasicBlock#getOutgoingSize () + */ + public int getOutgoingSize() { + return next.size(); + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.cdt.codan.provisional.core.model.cfg.IDecisionNode# + * getConnectionNode() + */ + public IConnectorNode getMergeNode() { + return conn; + } + + public void setMergeNode(IConnectorNode conn) { + this.conn = conn; + } +} diff --git a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/ExitNode.java b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/ExitNode.java new file mode 100644 index 0000000..7bd9848 --- /dev/null +++ b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/ExitNode.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2010 Alena Laskavaia and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alena Laskavaia - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.internal.core.cfg; + +import org.eclipse.cdt.codan.core.model.cfg.IBasicBlock; +import org.eclipse.cdt.codan.core.model.cfg.IExitNode; +import org.eclipse.cdt.codan.core.model.cfg.IStartNode; + +/** + * Plain node has one prev one jump + * + */ +public class ExitNode extends AbstractSingleIncomingNode implements IExitNode { + private IStartNode start; + + protected ExitNode() { + super(); + } + + public IBasicBlock[] getOutgoingNodes() { + return EMPTY_LIST; + } + + public int getOutgoingSize() { + return 0; + } + + public IStartNode getStartNode() { + return start; + } + + public void setStartNode(IStartNode start) { + this.start = start; + } + + @Override + public void addOutgoing(IBasicBlock node) { + throw new UnsupportedOperationException(); + } +} diff --git a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/JumpNode.java b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/JumpNode.java new file mode 100644 index 0000000..b5198d0 --- /dev/null +++ b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/JumpNode.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2010 Alena Laskavaia and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alena Laskavaia - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.internal.core.cfg; + +import org.eclipse.cdt.codan.core.model.cfg.IBasicBlock; +import org.eclipse.cdt.codan.core.model.cfg.IConnectorNode; +import org.eclipse.cdt.codan.core.model.cfg.IJumpNode; + +/** + * Jump node is node that connects unusual control pass, such as goto, break and + * continue + * + */ +public class JumpNode extends AbstractSingleIncomingNode implements IJumpNode { + private IConnectorNode jump; + private boolean backward; + + protected JumpNode() { + super(); + } + + public IBasicBlock[] getOutgoingNodes() { + return new IBasicBlock[] { jump }; + } + + public int getOutgoingSize() { + return 1; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.cdt.codan.core.model.cfg.IJumpNode#getJumpNode() + */ + public IConnectorNode getJumpNode() { + return jump; + } + + public IBasicBlock getOutgoing() { + return jump; + } + + public boolean isBackwardArc() { + return backward; + } + + public void setJump(IConnectorNode jump, boolean backward) { + if (this.jump != null && this.jump != jump) + throw new IllegalArgumentException( + "Cannot modify exiting connector"); //$NON-NLS-1$ + this.jump = jump; + this.backward = backward; + } + + public void setBackward(boolean backward) { + this.backward = backward; + } + + @Override + public void addOutgoing(IBasicBlock node) { + setJump((IConnectorNode) node, backward); + } +} diff --git a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/NodeFactory.java b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/NodeFactory.java new file mode 100644 index 0000000..0de0734 --- /dev/null +++ b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/NodeFactory.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 Alena Laskavaia + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alena Laskavaia - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.internal.core.cfg; + +import org.eclipse.cdt.codan.core.model.cfg.IBranchNode; +import org.eclipse.cdt.codan.core.model.cfg.IConnectorNode; +import org.eclipse.cdt.codan.core.model.cfg.IControlFlowGraph; +import org.eclipse.cdt.codan.core.model.cfg.IDecisionNode; +import org.eclipse.cdt.codan.core.model.cfg.IExitNode; +import org.eclipse.cdt.codan.core.model.cfg.IJumpNode; +import org.eclipse.cdt.codan.core.model.cfg.INodeFactory; +import org.eclipse.cdt.codan.core.model.cfg.IPlainNode; +import org.eclipse.cdt.codan.core.model.cfg.IStartNode; + +/** + * Factory that creates cfg nodes + */ +public class NodeFactory implements INodeFactory { + IControlFlowGraph graph; + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.cdt.codan.provisional.core.model.cfg.INodeFactory# + * getControlFlowGraph() + */ + public IControlFlowGraph getControlFlowGraph() { + return graph; + } + + public NodeFactory() { + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.cdt.codan.core.model.cfg.INodeFactory#createPlainNode () + */ + public IPlainNode createPlainNode() { + return new PlainNode(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.cdt.codan.core.model.cfg.INodeFactory#createJumpNode () + */ + public IJumpNode createJumpNode() { + return new JumpNode(); + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.cdt.codan.provisional.core.model.cfg.INodeFactory# + * createDecisionNode() + */ + public IDecisionNode createDecisionNode() { + return new DecisionNode(); + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.cdt.codan.provisional.core.model.cfg.INodeFactory# + * createConnectiorNode() + */ + public IConnectorNode createConnectorNode() { + return new ConnectorNode(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.cdt.codan.core.model.cfg.INodeFactory#createStartNode () + */ + public IStartNode createStartNode() { + return new StartNode(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.cdt.codan.core.model.cfg.INodeFactory#createExitNode () + */ + public IExitNode createExitNode() { + return new ExitNode(); + } + + public IBranchNode createBranchNode(String label) { + return new BranchNode(label); + } +} diff --git a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/PlainNode.java b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/PlainNode.java new file mode 100644 index 0000000..d382fb4 --- /dev/null +++ b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/PlainNode.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2010 Alena Laskavaia and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alena Laskavaia - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.internal.core.cfg; + +import org.eclipse.cdt.codan.core.model.cfg.IBasicBlock; +import org.eclipse.cdt.codan.core.model.cfg.IPlainNode; + +/** + * Plain node has one incoming arc and one outgoing arc + * + */ +public class PlainNode extends AbstractSingleIncomingNode implements IPlainNode { + protected IBasicBlock next; + + protected PlainNode() { + super(); + } + + public IBasicBlock[] getOutgoingNodes() { + return new IBasicBlock[] { next }; + } + + public int getOutgoingSize() { + return 1; + } + + public IBasicBlock getOutgoing() { + return next; + } + + public void setOutgoing(IBasicBlock exit) { + this.next = exit; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.cdt.codan.internal.core.cfg.AbstractBasicBlock#addOutgoing + * (org.eclipse.cdt.codan.core.model.cfg.IBasicBlock) + */ + @Override + public void addOutgoing(IBasicBlock node) { + setOutgoing(node); + } +} diff --git a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/StartNode.java b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/StartNode.java new file mode 100644 index 0000000..4d64bad --- /dev/null +++ b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/StartNode.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2010 Alena Laskavaia and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alena Laskavaia - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.internal.core.cfg; + +import org.eclipse.cdt.codan.core.model.cfg.IBasicBlock; +import org.eclipse.cdt.codan.core.model.cfg.IStartNode; + +/** + * Start node has no incoming, one outgoing and it is connect to function exits + * + */ +public class StartNode extends AbstractSingleOutgoingNode implements IStartNode { + protected StartNode() { + super(); + } + + public IBasicBlock[] getIncomingNodes() { + return EMPTY_LIST; + } + + public int getIncomingSize() { + return 0; + } + + @Override + public void addOutgoing(IBasicBlock node) { + setOutgoing(node); + } + + @Override + public void addIncoming(IBasicBlock node) { + throw new UnsupportedOperationException(); + } +} diff --git a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CVS/Entries b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CVS/Entries index 5f7a029..182ee54 100644 --- a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CVS/Entries +++ b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CVS/Entries @@ -1,5 +1,6 @@ -/CodanMarkerProblemReporter.java/1.2/Wed Dec 16 21:48:48 2009// -/CodanProblem.java/1.1/Sat Aug 22 21:16:48 2009// -/CodanProblemCategory.java/1.2/Wed Dec 16 21:48:48 2009// -/ProblemProfile.java/1.1/Wed Sep 23 23:29:36 2009// -D +/CodanMarkerProblemReporter.java/1.15/Sun Jun 27 01:30:42 2010//TCDT_7_0_0 +/CodanProblem.java/1.9/Sun Jun 27 01:30:42 2010//TCDT_7_0_0 +/CodanProblemCategory.java/1.4/Sun Jun 27 01:30:42 2010//TCDT_7_0_0 +/CodanProblemLocation.java/1.4/Sun Jun 27 01:30:42 2010//TCDT_7_0_0 +/ProblemLocationFactory.java/1.3/Sun Jun 27 01:30:42 2010//TCDT_7_0_0 +/ProblemProfile.java/1.3/Sun Jun 27 01:30:42 2010//TCDT_7_0_0 diff --git a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CVS/Tag b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CVS/Tag new file mode 100644 index 0000000..49a449a --- /dev/null +++ b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CVS/Tag @@ -0,0 +1 @@ +NCDT_7_0_0 diff --git a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CodanMarkerProblemReporter.java b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CodanMarkerProblemReporter.java index a4599c5..51a4794 100644 --- a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CodanMarkerProblemReporter.java +++ b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CodanMarkerProblemReporter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009 Alena Laskavaia + * Copyright (c) 2009, 2010 Alena Laskavaia * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -11,39 +11,40 @@ package org.eclipse.cdt.codan.internal.core.model; import java.text.MessageFormat; +import java.util.Collection; +import java.util.Iterator; +import org.eclipse.cdt.codan.core.CodanCorePlugin; +import org.eclipse.cdt.codan.core.CodanRuntime; +import org.eclipse.cdt.codan.core.model.IChecker; +import org.eclipse.cdt.codan.core.model.ICheckersRegistry; import org.eclipse.cdt.codan.core.model.IProblem; import org.eclipse.cdt.codan.core.model.IProblemLocation; -import org.eclipse.cdt.codan.core.model.IProblemReporter; -import org.eclipse.cdt.codan.internal.core.CheckersRegisry; -import org.eclipse.core.resources.IFile; +import org.eclipse.cdt.codan.core.model.IProblemReporterPersistent; +import org.eclipse.cdt.codan.internal.core.CheckersRegistry; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.resources.IWorkspaceRunnable; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; -public class CodanMarkerProblemReporter implements IProblemReporter { - - - /* - * (non-Javadoc) - * - * @see - * org.eclipse.cdt.codan.core.model.IProblemReporter#reportProblem(java. - * lang.String, org.eclipse.cdt.codan.core.model.IProblemLocation, - * java.lang.Object[]) - */ +/** + * Problem reported that created eclipse markers + */ +public class CodanMarkerProblemReporter implements IProblemReporterPersistent { public void reportProblem(String id, IProblemLocation loc, Object... args) { - IFile file = loc.getFile(); + IResource file = loc.getFile(); int lineNumber = loc.getLineNumber(); if (file == null) - throw new NullPointerException("file"); + throw new NullPointerException("file"); //$NON-NLS-1$ if (id == null) - throw new NullPointerException("id"); - IProblem problem = CheckersRegisry.getInstance().getResourceProfile( - file).findProblem(id); + throw new NullPointerException("id"); //$NON-NLS-1$ + IProblem problem = CheckersRegistry.getInstance() + .getResourceProfile(file).findProblem(id); if (problem == null) - throw new IllegalArgumentException("Id is not registered"); + throw new IllegalArgumentException("Id is not registered:" + id); //$NON-NLS-1$ if (problem.isEnabled() == false) return; // skip int severity = problem.getSeverity().intValue(); @@ -53,25 +54,31 @@ public class CodanMarkerProblemReporter implements IProblemReporter { if (args != null && args.length > 0 && args[0] instanceof String) message = (String) args[0]; } else { - MessageFormat.format(messagePattern, args); + message = MessageFormat.format(messagePattern, args); } - reportProblem(id, severity, file, lineNumber, loc.getStartingChar(), - loc.getEndingChar(), message); + reportProblem(id, problem.getMarkerType(), severity, file, lineNumber, + loc.getStartingChar(), loc.getEndingChar(), message); } - /* - * (non-Javadoc) - * - * @see - * org.eclipse.cdt.codan.core.model.IProblemReporter#reportProblem(java. - * lang.String, org.eclipse.core.resources.IFile, int, java.lang.String) + /** + * @param id - problem id + * @param markerType - marker id + * @param severity - marker severity + * @param file - resource + * @param lineNumber - line number for error + * @param startChar - start char (offset in charts from the begging of the + * document) + * @param endChar - end char (offset in charts from the begging of the + * document, exclusive) + * @param message - marker message */ - public void reportProblem(String id, int severity, IFile file, - int lineNumber, int startChar, int endChar, String message) { + public void reportProblem(String id, String markerType, int severity, + IResource file, int lineNumber, int startChar, int endChar, + String message) { try { // Do not put in duplicates - IMarker[] cur = file.findMarkers(GENERIC_CODE_ANALYSIS_MARKER_TYPE, - false, IResource.DEPTH_ZERO); + IMarker[] cur = file.findMarkers(markerType, false, + IResource.DEPTH_ZERO); if (cur != null) { for (IMarker element : cur) { int line = ((Integer) element @@ -86,37 +93,72 @@ public class CodanMarkerProblemReporter implements IProblemReporter { } } } - IMarker marker = file - .createMarker(GENERIC_CODE_ANALYSIS_MARKER_TYPE); + IMarker marker = file.createMarker(markerType); marker.setAttribute(IMarker.MESSAGE, message); marker.setAttribute(IMarker.SEVERITY, severity); marker.setAttribute(IMarker.LINE_NUMBER, lineNumber); marker.setAttribute(IMarker.PROBLEM, id); marker.setAttribute(IMarker.CHAR_END, endChar); marker.setAttribute(IMarker.CHAR_START, startChar); + marker.setAttribute("org.eclipse.cdt.core.problem", 42); //$NON-NLS-1$ } catch (CoreException e) { e.printStackTrace(); } } - public void deleteMarkers(IResource file) { + public void deleteProblems(IResource file) { try { - file.deleteMarkers(GENERIC_CODE_ANALYSIS_MARKER_TYPE, false, + file.deleteMarkers(GENERIC_CODE_ANALYSIS_MARKER_TYPE, true, IResource.DEPTH_ZERO); } catch (CoreException ce) { ce.printStackTrace(); } } - public void deleteAllMarkers() { + public void deleteAllProblems() { try { - // TODO delete contributed markers too - ResourcesPlugin.getWorkspace().getRoot().deleteMarkers( - GENERIC_CODE_ANALYSIS_MARKER_TYPE, false, - IResource.DEPTH_INFINITE); + ResourcesPlugin + .getWorkspace() + .getRoot() + .deleteMarkers(GENERIC_CODE_ANALYSIS_MARKER_TYPE, true, + IResource.DEPTH_INFINITE); } catch (CoreException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + CodanCorePlugin.log(e); + } + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.cdt.codan.core.model.IProblemReporterPersistent#deleteProblems + * (org.eclipse.core.resources.IResource, + * org.eclipse.cdt.codan.core.model.IChecker) + */ + public void deleteProblems(final IResource file, final IChecker checker) { + try { + ResourcesPlugin.getWorkspace().run(new IWorkspaceRunnable() { + public void run(IProgressMonitor monitor) throws CoreException { + IMarker[] markers = file.findMarkers( + GENERIC_CODE_ANALYSIS_MARKER_TYPE, true, + IResource.DEPTH_INFINITE); + ICheckersRegistry reg = CodanRuntime.getInstance() + .getChechersRegistry(); + for (int i = 0; i < markers.length; i++) { + IMarker m = markers[i]; + String id = m.getAttribute(IMarker.PROBLEM, ""); //$NON-NLS-1$ + Collection<IProblem> problems = reg.getRefProblems(checker); + for (Iterator<IProblem> iterator = problems.iterator(); iterator + .hasNext();) { + IProblem iProblem = iterator.next(); + if (iProblem.getId().equals(id)) + m.delete(); + } + } + } + }, null, IWorkspace.AVOID_UPDATE, null); + } catch (CoreException e) { + CodanCorePlugin.log(e); } } } diff --git a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CodanProblem.java b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CodanProblem.java index a094cc1..56b43c5 100644 --- a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CodanProblem.java +++ b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CodanProblem.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009 Alena Laskavaia + * Copyright (c) 2009, 2010 Alena Laskavaia * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -10,20 +10,21 @@ *******************************************************************************/ package org.eclipse.cdt.codan.internal.core.model; -import java.util.Collection; -import java.util.HashMap; - import org.eclipse.cdt.codan.core.model.CodanSeverity; -import org.eclipse.cdt.codan.core.model.IProblem; -import org.eclipse.cdt.codan.core.model.IProblemCategory; +import org.eclipse.cdt.codan.core.model.IProblemReporter; +import org.eclipse.cdt.codan.core.model.IProblemWorkingCopy; +import org.eclipse.cdt.codan.core.param.IProblemPreference; -public class CodanProblem implements IProblem { +public class CodanProblem implements IProblemWorkingCopy { private String id; private String name; private String message; private CodanSeverity severity = CodanSeverity.Warning; private boolean enabled = true; - private HashMap<Object, Object> properties = new HashMap<Object, Object>(0); + private IProblemPreference preference; + private boolean frozen; + private String description; + private String markerType = IProblemReporter.GENERIC_CODE_ANALYSIS_MARKER_TYPE; public CodanSeverity getSeverity() { return severity; @@ -32,6 +33,7 @@ public class CodanProblem implements IProblem { public CodanProblem(String problemId, String name) { this.id = problemId; this.name = name; + this.frozen = false; } public String getName() { @@ -42,11 +44,6 @@ public class CodanProblem implements IProblem { return id; } - public IProblemCategory getCategory() { - // TODO Auto-generated method stub - return null; - } - @Override public String toString() { return name; @@ -73,19 +70,19 @@ public class CodanProblem implements IProblem { */ @Override public Object clone() throws CloneNotSupportedException { - return super.clone(); + CodanProblem prob = (CodanProblem) super.clone(); + if (preference != null) { + prob.preference = (IProblemPreference) preference.clone(); + } + return prob; } - public void setProperty(Object key, Object value) { - properties.put(key, value); + public void setPreference(IProblemPreference value) { + preference = value; } - public Object getProperty(Object key) { - return properties.get(key); - }; - - public Collection<Object> getPropertyKeys() { - return properties.keySet(); + public IProblemPreference getPreference() { + return preference; } /* @@ -97,10 +94,54 @@ public class CodanProblem implements IProblem { return message; } + protected void freeze() { + frozen = true; + } + /** - * @param message the message to set + * @param message + * the message to set */ public void setMessagePattern(String message) { + checkSet(); this.message = message; } + + protected void checkSet() { + if (frozen) + throw new IllegalStateException("Object is unmodifieble"); //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.cdt.codan.core.model.IProblem#getDescription() + */ + public String getDescription() { + return description; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.cdt.codan.core.model.IProblemWorkingCopy#setDescription(java + * .lang.String) + */ + public void setDescription(String desc) { + this.description = desc; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.cdt.codan.core.model.IProblem#getMarkerType() + */ + public String getMarkerType() { + return markerType; + } + + public void setMarkerType(String type) { + markerType = type; + } } diff --git a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CodanProblemCategory.java b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CodanProblemCategory.java index fc63480..0156211 100644 --- a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CodanProblemCategory.java +++ b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CodanProblemCategory.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009 Alena Laskavaia + * Copyright (c) 2009, 2010 Alena Laskavaia * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -41,40 +41,36 @@ public class CodanProblemCategory implements IProblemCategory, Cloneable { } public IProblemElement[] getChildren() { - return (IProblemElement[]) list.toArray(new IProblemElement[list.size()]); + return list.toArray(new IProblemElement[list.size()]); } public void addChild(IProblemElement p) { list.add(p); } - public IProblem findProblem(String id) { - Object[] children = this.getChildren(); + public static IProblem findProblem(IProblemCategory c, String id) { + Object[] children = c.getChildren(); for (Object object : children) { if (object instanceof IProblemCategory) { IProblemCategory cat = (IProblemCategory) object; - IProblem found = cat.findProblem(id); - if (found != null) - return found; + IProblem found = findProblem(cat, id); + if (found != null) return found; } else if (object instanceof IProblem) { IProblem p = (IProblem) object; - if (p.getId().equals(id)) - return p; + if (p.getId().equals(id)) return p; } } return null; } - public IProblemCategory findCategory(String id) { - if (getId().equals(id)) - return this; - Object[] children = getChildren(); + public static IProblemCategory findCategory(IProblemCategory cat, String id) { + if (cat.getId().equals(id)) return cat; + Object[] children = cat.getChildren(); for (Object object : children) { if (object instanceof IProblemCategory) { - IProblemCategory cat = (IProblemCategory) object; - IProblemCategory found = cat.findCategory(id); - if (found != null) - return found; + IProblemCategory cat2 = (IProblemCategory) object; + IProblemCategory found = findCategory(cat2, id); + if (found != null) return found; } } return null; @@ -90,8 +86,7 @@ public class CodanProblemCategory implements IProblemCategory, Cloneable { try { CodanProblemCategory clone = (CodanProblemCategory) super.clone(); clone.list = new ArrayList<IProblemElement>(); - for (Iterator<IProblemElement> iterator = this.list.iterator(); iterator - .hasNext();) { + for (Iterator<IProblemElement> iterator = this.list.iterator(); iterator.hasNext();) { IProblemElement child = iterator.next(); clone.list.add((IProblemElement) child.clone()); } diff --git a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CodanProblemLocation.java b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CodanProblemLocation.java new file mode 100644 index 0000000..ca6bd02 --- /dev/null +++ b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CodanProblemLocation.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 Alena Laskavaia + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alena Laskavaia - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.internal.core.model; + +import org.eclipse.cdt.codan.core.model.AbstractProblemLocation; +import org.eclipse.core.resources.IFile; + +/** + * Codan Problem Location, so far same as abstract class + * + */ +public class CodanProblemLocation extends AbstractProblemLocation { + public CodanProblemLocation(IFile file, int startChar, int endChar) { + super(file, startChar, endChar); + } + + public CodanProblemLocation(IFile file, int startChar, int endChar, int line) { + super(file, startChar, endChar); + this.line = line; + } + + protected CodanProblemLocation(IFile file, int line) { + super(file, line); + } +} diff --git a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/ProblemLocationFactory.java b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/ProblemLocationFactory.java new file mode 100644 index 0000000..835f6bf --- /dev/null +++ b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/ProblemLocationFactory.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 Alena Laskavaia + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alena Laskavaia - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.internal.core.model; + +import org.eclipse.cdt.codan.core.model.IProblemLocation; +import org.eclipse.cdt.codan.core.model.IProblemLocationFactory; +import org.eclipse.core.resources.IFile; + +/** + * Factory class that allows to create problem locations + * + */ +public class ProblemLocationFactory implements IProblemLocationFactory { + /* + * (non-Javadoc) + * + * @seeorg.eclipse.cdt.codan.core.model.IProblemLocationFactory# + * createProblemLocation(org.eclipse.core.resources.IFile, int) + */ + public IProblemLocation createProblemLocation(IFile file, int line) { + return new CodanProblemLocation(file, line); + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.cdt.codan.core.model.IProblemLocationFactory# + * createProblemLocation(org.eclipse.core.resources.IFile, int, int) + */ + public IProblemLocation createProblemLocation(IFile file, int startChar, + int endChar) { + return new CodanProblemLocation(file, startChar, endChar); + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.cdt.codan.core.model.IProblemLocationFactory# + * createProblemLocation(org.eclipse.core.resources.IFile, int, int, int) + */ + public IProblemLocation createProblemLocation(IFile file, int startChar, + int endChar, int line) { + return new CodanProblemLocation(file, startChar, endChar, line); + } +} diff --git a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/ProblemProfile.java b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/ProblemProfile.java index d2330f1..1eb045b 100644 --- a/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/ProblemProfile.java +++ b/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/ProblemProfile.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009 Alena Laskavaia + * Copyright (c) 2009, 2010 Alena Laskavaia * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -22,8 +22,7 @@ import org.eclipse.cdt.codan.core.model.IProblemProfile; * */ public class ProblemProfile implements IProblemProfile, Cloneable { - private IProblemCategory rootCategory = new CodanProblemCategory("root", - "root"); + private IProblemCategory rootCategory = new CodanProblemCategory("root", "root"); //$NON-NLS-1$ //$NON-NLS-2$ /* * (non-Javadoc) @@ -33,7 +32,7 @@ public class ProblemProfile implements IProblemProfile, Cloneable { * .String) */ public IProblem findProblem(String id) { - return getRoot().findProblem(id); + return CodanProblemCategory.findProblem(getRoot(), id); } /* @@ -51,8 +50,7 @@ public class ProblemProfile implements IProblemProfile, Cloneable { * @param root * @param problems */ - protected void collectProblems(IProblemCategory parent, - Collection<IProblem> problems) { + protected void collectProblems(IProblemCategory parent, Collection<IProblem> problems) { Object[] children = parent.getChildren(); for (Object object : children) { if (object instanceof IProblemCategory) { @@ -69,13 +67,12 @@ public class ProblemProfile implements IProblemProfile, Cloneable { } public void addProblem(IProblem p, IProblemCategory cat) { - if (cat == null) - cat = getRoot(); + if (cat == null) cat = getRoot(); ((CodanProblemCategory) cat).addChild(p); } public IProblemCategory findCategory(String id) { - return getRoot().findCategory(id); + return CodanProblemCategory.findCategory(getRoot(), id); } /* @@ -87,8 +84,7 @@ public class ProblemProfile implements IProblemProfile, Cloneable { public Object clone() { try { ProblemProfile clone = (ProblemProfile) super.clone(); - clone.rootCategory = (IProblemCategory) ((CodanProblemCategory) this.rootCategory) - .clone(); + clone.rootCategory = (IProblemCategory) ((CodanProblemCategory) this.rootCategory).clone(); return clone; } catch (CloneNotSupportedException e) { return this; |