| /******************************************************************************* |
| * Copyright (c) 2010, 2017 xored software, Inc. |
| * |
| * 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: |
| * xored software, Inc. - initial API and Implementation (Alex Panchenko) |
| *******************************************************************************/ |
| package org.eclipse.dltk.core.search.matching2; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.regex.Pattern; |
| |
| import org.eclipse.dltk.compiler.CharOperation; |
| import org.eclipse.dltk.core.search.SearchPattern; |
| import org.eclipse.dltk.internal.core.search.matching.DLTKSearchPattern; |
| |
| public abstract class AbstractMatchingPredicate<E> |
| implements IMatchingPredicate<E> { |
| |
| private final boolean isCaseSensitive; |
| private final boolean isCamelCase; |
| // private final boolean isErasureMatch; |
| // private final boolean isEquivalentMatch; |
| private final int matchMode; |
| |
| protected final char[] namePattern; |
| |
| public AbstractMatchingPredicate(SearchPattern pattern, |
| char[] namePattern) { |
| int matchRule = pattern.getMatchRule(); |
| this.isCaseSensitive = (matchRule |
| & SearchPattern.R_CASE_SENSITIVE) != 0; |
| this.isCamelCase = (matchRule & SearchPattern.R_CAMELCASE_MATCH) != 0; |
| // this.isErasureMatch = (matchRule & SearchPattern.R_ERASURE_MATCH) != |
| // 0; |
| // this.isEquivalentMatch = (matchRule & |
| // SearchPattern.R_EQUIVALENT_MATCH) != 0; |
| this.matchMode = matchRule & DLTKSearchPattern.MATCH_MODE_MASK; |
| this.namePattern = namePattern; |
| } |
| |
| protected MatchLevel matchName(String name) { |
| return matchNameValue(namePattern, name.toCharArray()); |
| } |
| |
| private Pattern compiledPattern; |
| |
| protected MatchLevel matchNameValue(char[] pattern, char[] name) { |
| if (pattern == null) |
| return MatchLevel.ACCURATE_MATCH; // null is as if it was "*" |
| if (name == null) |
| return null; // cannot match null name |
| if (name.length == 0) { // empty name |
| if (pattern.length == 0) { // can only matches empty pattern |
| return MatchLevel.ACCURATE_MATCH; |
| } |
| return null; |
| } else if (pattern.length == 0) { |
| return null; // need to have both name and pattern |
| // length==0 to be accurate |
| } |
| boolean matchFirstChar = !this.isCaseSensitive || pattern[0] == name[0]; |
| boolean sameLength = pattern.length == name.length; |
| boolean canBePrefix = name.length >= pattern.length; |
| if (this.isCamelCase && matchFirstChar |
| && CharOperation.camelCaseMatch(pattern, name)) { |
| return MatchLevel.POSSIBLE_MATCH; |
| } |
| switch (this.matchMode) { |
| case SearchPattern.R_EXACT_MATCH: |
| if (!this.isCamelCase) { |
| if (sameLength && matchFirstChar && CharOperation |
| .equals(pattern, name, this.isCaseSensitive)) { |
| return MatchLevel.POSSIBLE_MATCH; |
| } |
| break; |
| } |
| // fall through next case to match as prefix if camel case |
| // failed |
| case SearchPattern.R_PREFIX_MATCH: |
| if (canBePrefix && matchFirstChar && CharOperation |
| .prefixEquals(pattern, name, this.isCaseSensitive)) { |
| return MatchLevel.POSSIBLE_MATCH; |
| } |
| break; |
| case SearchPattern.R_PATTERN_MATCH: |
| if (!this.isCaseSensitive) { |
| pattern = CharOperation.toLowerCase(pattern); |
| } |
| if (CharOperation.match(pattern, name, this.isCaseSensitive)) { |
| return MatchLevel.POSSIBLE_MATCH; |
| } |
| break; |
| case SearchPattern.R_REGEXP_MATCH: |
| if (compiledPattern == null) { |
| compiledPattern = Pattern.compile(new String(pattern), |
| this.isCaseSensitive ? 0 : Pattern.CASE_INSENSITIVE); |
| } |
| if (compiledPattern.matcher(new String(name)).matches()) { |
| return MatchLevel.POSSIBLE_MATCH; |
| } |
| break; |
| } |
| return null; |
| } |
| |
| @Override |
| public String toString() { |
| final StringBuilder sb = new StringBuilder(); |
| sb.append(getClass().getSimpleName()); |
| sb.append("("); |
| sb.append(namePattern != null ? new String(namePattern) : "*"); |
| final List<String> options = new ArrayList<>(); |
| collectToStringOptions(options); |
| if (!options.isEmpty()) { |
| sb.append(":"); |
| boolean first = true; |
| for (String option : options) { |
| if (!first) { |
| sb.append(','); |
| } |
| sb.append(option); |
| first = false; |
| } |
| } |
| sb.append(")"); |
| return sb.toString(); |
| } |
| |
| protected void collectToStringOptions(List<String> options) { |
| } |
| |
| @Override |
| public MatchLevel resolvePotentialMatch(E node) { |
| return MatchLevel.INACCURATE_MATCH; |
| } |
| |
| @Override |
| public boolean contains(IMatchingPredicate<E> predicate) { |
| return false; |
| } |
| |
| /** |
| * Calls {@link #matchName(String)} and upgrades |
| * {@link MatchLevel#POSSIBLE_MATCH} to the specified value. |
| */ |
| protected MatchLevel matchName(String name, MatchLevel upgraded) { |
| final MatchLevel level = matchName(name); |
| return level == MatchLevel.POSSIBLE_MATCH ? upgraded : level; |
| } |
| |
| } |