blob: f31087d84e7dac8b6d1dd2bc7d576e771ec2c2f2 [file] [log] [blame]
// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
public class ProguardPackageMatcher {
private final String pattern;
public ProguardPackageMatcher(String pattern) {
this.pattern = pattern;
}
public boolean matches(String packageName) {
return matchPackageNameImpl(pattern, 0, packageName, 0);
}
private static boolean matchPackageNameImpl(
String pattern, int patternIndex, String name, int nameIndex) {
for (int i = patternIndex; i < pattern.length(); i++) {
char patternChar = pattern.charAt(i);
switch (patternChar) {
case '*':
int nextPatternIndex = i + 1;
// Check for **.
boolean includeSeparators =
pattern.length() > (nextPatternIndex) && pattern.charAt(nextPatternIndex) == '*';
if (includeSeparators) {
nextPatternIndex += 1;
}
// Fast cases for the common case where a pattern ends with '*' or '**'.
if (nextPatternIndex == pattern.length()) {
if (includeSeparators) {
return true;
}
boolean hasSeparators = containsSeparatorsStartingAt(name, nameIndex);
return !hasSeparators;
}
// Match the rest of the pattern against the (non-empty) rest of the class name.
for (int nextNameIndex = nameIndex; nextNameIndex < name.length(); nextNameIndex++) {
if (!includeSeparators) {
// Stop at the first separator for just *.
if (name.charAt(nextNameIndex) == '.') {
return matchPackageNameImpl(pattern, nextPatternIndex, name, nextNameIndex);
}
}
if (matchPackageNameImpl(pattern, nextPatternIndex, name, nextNameIndex)) {
return true;
}
}
// Finally, check the case where the '*' or '**' eats all of the package name.
return matchPackageNameImpl(pattern, nextPatternIndex, name, name.length());
case '?':
if (nameIndex == name.length() || name.charAt(nameIndex) == '.') {
return false;
}
nameIndex++;
break;
default:
if (nameIndex == name.length() || patternChar != name.charAt(nameIndex++)) {
return false;
}
break;
}
}
return nameIndex == name.length();
}
private static boolean containsSeparatorsStartingAt(String className, int nameIndex) {
return className.indexOf('.', nameIndex) != -1;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof ProguardPackageMatcher)) {
return false;
}
ProguardPackageMatcher other = (ProguardPackageMatcher) o;
return pattern.equals(other.pattern);
}
@Override
public int hashCode() {
return pattern.hashCode();
}
}