patternMatcher: Just return 'undefined' for an invalid pattern (#23237)

* patternMatcher: Just return 'undefined' for an invalid pattern

* Fix tests
This commit is contained in:
Andy
2018-04-10 14:38:16 -07:00
committed by GitHub
parent 22919d57fe
commit f479de6d02
3 changed files with 13 additions and 23 deletions

View File

@@ -343,15 +343,11 @@ describe("PatternMatcher", () => {
});
it("BlankPattern", () => {
const matches = getAllMatches("AddMetadataReference", "");
assert.isTrue(matches === undefined);
assertInvalidPattern("");
});
it("WhitespaceOnlyPattern", () => {
const matches = getAllMatches("AddMetadataReference", " ");
assert.isTrue(matches === undefined);
assertInvalidPattern(" ");
});
it("EachWordSeparately1", () => {
@@ -449,6 +445,10 @@ describe("PatternMatcher", () => {
});
});
function assertInvalidPattern(pattern: string) {
assert.equal(ts.createPatternMatcher(pattern), undefined);
}
function getFirstMatch(candidate: string, pattern: string): ts.PatternMatch {
const matches = ts.createPatternMatcher(pattern).getMatchesForLastSegmentOfPattern(candidate);
return matches ? matches[0] : undefined;

View File

@@ -10,6 +10,7 @@ namespace ts.NavigateTo {
export function getNavigateToItems(sourceFiles: ReadonlyArray<SourceFile>, checker: TypeChecker, cancellationToken: CancellationToken, searchValue: string, maxResultCount: number, excludeDtsFiles: boolean): NavigateToItem[] {
const patternMatcher = createPatternMatcher(searchValue);
if (!patternMatcher) return emptyArray;
let rawItems: RawNavigateToItem[] = [];
// Search the declarations in all files and output matched NavigateToItem into array of NavigateToItem[]

View File

@@ -97,28 +97,22 @@ namespace ts {
};
}
export function createPatternMatcher(pattern: string): PatternMatcher {
export function createPatternMatcher(pattern: string): PatternMatcher | undefined {
// We'll often see the same candidate string many times when searching (For example, when
// we see the name of a module that is used everywhere, or the name of an overload). As
// such, we cache the information we compute about the candidate for the life of this
// pattern matcher so we don't have to compute it multiple times.
const stringToWordSpans = createMap<TextSpan[]>();
pattern = pattern.trim();
const dotSeparatedSegments = pattern.split(".").map(p => createSegment(p.trim()));
const invalidPattern = dotSeparatedSegments.length === 0 || forEach(dotSeparatedSegments, segmentIsInvalid);
const dotSeparatedSegments = pattern.trim().split(".").map(p => createSegment(p.trim()));
// A segment is considered invalid if we couldn't find any words in it.
if (dotSeparatedSegments.some(segment => !segment.subWordTextChunks.length)) return undefined;
return {
getMatches: (containers, candidate) => skipMatch(candidate) ? undefined : getMatches(containers, candidate, dotSeparatedSegments, stringToWordSpans),
getMatchesForLastSegmentOfPattern: candidate => skipMatch(candidate) ? undefined : matchSegment(candidate, lastOrUndefined(dotSeparatedSegments), stringToWordSpans),
getMatches: (containers, candidate) => getMatches(containers, candidate, dotSeparatedSegments, stringToWordSpans),
getMatchesForLastSegmentOfPattern: candidate => matchSegment(candidate, last(dotSeparatedSegments), stringToWordSpans),
patternContainsDots: dotSeparatedSegments.length > 1
};
// Quick checks so we can bail out when asked to match a candidate.
function skipMatch(candidate: string) {
return invalidPattern || !candidate;
}
}
function getMatches(candidateContainers: ReadonlyArray<string>, candidate: string, dotSeparatedSegments: ReadonlyArray<Segment>, stringToWordSpans: Map<TextSpan[]>): PatternMatch[] | undefined {
@@ -381,11 +375,6 @@ namespace ts {
};
}
// A segment is considered invalid if we couldn't find any words in it.
function segmentIsInvalid(segment: Segment) {
return segment.subWordTextChunks.length === 0;
}
function isUpperCaseLetter(ch: number) {
// Fast check for the ascii range.
if (ch >= CharacterCodes.A && ch <= CharacterCodes.Z) {