From c9b550bf8e90956df505b3c3d470e383101411df Mon Sep 17 00:00:00 2001 From: Rob Stryker Date: Thu, 16 Nov 2023 15:07:58 -0500 Subject: [PATCH] Fixes #2960 - remove duplicate org.eclipse.search classes Signed-off-by: Rob Stryker --- org.eclipse.jdt.ls.core/META-INF/MANIFEST.MF | 3 +- .../refactoring/util/QualifiedNameFinder.java | 8 +- .../search/text/DocumentCharSequence.java | 57 -- .../search/text/FileCharSequenceProvider.java | 487 --------------- .../text/FileNamePatternSearchScope.java | 184 ------ .../search/text/FilesOfScopeCalculator.java | 66 --- .../search/text/PatternConstructor.java | 514 ---------------- .../search/text/TextSearchEngine.java | 113 ---- .../search/text/TextSearchMatchAccess.java | 85 --- .../search/text/TextSearchRequestor.java | 162 ----- .../internal/search/text/TextSearchScope.java | 87 --- .../search/text/TextSearchVisitor.java | 558 ------------------ 12 files changed, 6 insertions(+), 2318 deletions(-) delete mode 100644 org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/DocumentCharSequence.java delete mode 100644 org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/FileCharSequenceProvider.java delete mode 100644 org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/FileNamePatternSearchScope.java delete mode 100644 org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/FilesOfScopeCalculator.java delete mode 100644 org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/PatternConstructor.java delete mode 100644 org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/TextSearchEngine.java delete mode 100644 org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/TextSearchMatchAccess.java delete mode 100644 org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/TextSearchRequestor.java delete mode 100644 org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/TextSearchScope.java delete mode 100644 org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/TextSearchVisitor.java diff --git a/org.eclipse.jdt.ls.core/META-INF/MANIFEST.MF b/org.eclipse.jdt.ls.core/META-INF/MANIFEST.MF index dae515a5ff..00cf685f7a 100644 --- a/org.eclipse.jdt.ls.core/META-INF/MANIFEST.MF +++ b/org.eclipse.jdt.ls.core/META-INF/MANIFEST.MF @@ -30,7 +30,8 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="3.12.0", org.eclipse.xtext.xbase.lib, org.eclipse.core.filesystem;bundle-version="1.7.0", org.eclipse.jdt.apt.pluggable.core;bundle-version="1.2.0";resolution:=optional, - org.eclipse.m2e.apt.core;bundle-version="1.3.0";resolution:=optional + org.eclipse.m2e.apt.core;bundle-version="1.3.0";resolution:=optional, + org.eclipse.search.core;bundle-version="3.16.0" Export-Package: org.eclipse.jdt.ls.core.contentassist;x-friends:="org.eclipse.jdt.ls.tests", org.eclipse.jdt.ls.core.internal;x-friends:="org.eclipse.jdt.ls.tests,org.eclipse.jdt.ls.tests.syntaxserver", org.eclipse.jdt.ls.core.internal.cleanup;x-friends:="org.eclipse.jdt.ls.tests", diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corext/refactoring/util/QualifiedNameFinder.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corext/refactoring/util/QualifiedNameFinder.java index 54c4466164..21a886d65c 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corext/refactoring/util/QualifiedNameFinder.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corext/refactoring/util/QualifiedNameFinder.java @@ -35,13 +35,13 @@ import org.eclipse.jdt.internal.corext.refactoring.changes.TextChangeCompatibility; import org.eclipse.jdt.ls.core.internal.corext.util.PatternConstructor; import org.eclipse.jdt.ls.core.internal.corext.util.QualifiedNameSearchResult; -import org.eclipse.jdt.ls.core.internal.search.text.TextSearchEngine; -import org.eclipse.jdt.ls.core.internal.search.text.TextSearchMatchAccess; -import org.eclipse.jdt.ls.core.internal.search.text.TextSearchRequestor; -import org.eclipse.jdt.ls.core.internal.search.text.TextSearchScope; import org.eclipse.ltk.core.refactoring.GroupCategory; import org.eclipse.ltk.core.refactoring.GroupCategorySet; import org.eclipse.ltk.core.refactoring.TextChange; +import org.eclipse.search.core.text.TextSearchEngine; +import org.eclipse.search.core.text.TextSearchMatchAccess; +import org.eclipse.search.core.text.TextSearchRequestor; +import org.eclipse.search.core.text.TextSearchScope; import org.eclipse.text.edits.ReplaceEdit; public class QualifiedNameFinder { diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/DocumentCharSequence.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/DocumentCharSequence.java deleted file mode 100644 index 3a32b099e4..0000000000 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/DocumentCharSequence.java +++ /dev/null @@ -1,57 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Originally copied from org.eclipse.search.internal.core.text.DocumentCharSequence - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.ls.core.internal.search.text; - -import org.eclipse.jface.text.BadLocationException; -import org.eclipse.jface.text.IDocument; - -/** - * Adapting a document to a CharSequence - */ -public class DocumentCharSequence implements CharSequence { - - private final IDocument fDocument; - - /** - * @param document The document to wrap - */ - public DocumentCharSequence(IDocument document) { - fDocument= document; - } - - @Override - public int length() { - return fDocument.getLength(); - } - - @Override - public char charAt(int index) { - try { - return fDocument.getChar(index); - } catch (BadLocationException e) { - throw new IndexOutOfBoundsException(); - } - } - - @Override - public CharSequence subSequence(int start, int end) { - try { - return fDocument.get(start, end - start); - } catch (BadLocationException e) { - throw new IndexOutOfBoundsException(); - } - } - -} diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/FileCharSequenceProvider.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/FileCharSequenceProvider.java deleted file mode 100644 index 2cc4131859..0000000000 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/FileCharSequenceProvider.java +++ /dev/null @@ -1,487 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2010 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Originally copied from org.eclipse.search.internal.core.text.FileCharSequenceProvider - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.ls.core.internal.search.text; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.util.Arrays; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.content.IContentDescription; - -/** - * - */ -public class FileCharSequenceProvider { - - private static int NUMBER_OF_BUFFERS= 3; - public static int BUFFER_SIZE= 2 << 18; // public for testing - - private FileCharSequence fReused= null; - - public CharSequence newCharSequence(IFile file) throws CoreException, IOException { - if (fReused == null) { - return new FileCharSequence(file); - } - FileCharSequence curr= fReused; - fReused= null; - curr.reset(file); - return curr; - } - - public void releaseCharSequence(CharSequence seq) throws IOException { - if (seq instanceof FileCharSequence curr) { - try { - curr.close(); - } finally { - if (fReused == null) { - fReused= curr; - } - } - } - } - - public static class FileCharSequenceException extends RuntimeException { - private static final long serialVersionUID= 1L; - - /* package */ FileCharSequenceException(IOException e) { - super(e); - } - - /* package */ FileCharSequenceException(CoreException e) { - super(e); - } - - public void throwWrappedException() throws CoreException, IOException { - Throwable wrapped= getCause(); - if (wrapped instanceof CoreException coreEx) { - throw coreEx; - } else if (wrapped instanceof IOException ioEx) { - throw ioEx; - } - // not possible - } - } - - - private static final class CharSubSequence implements CharSequence { - - private final int fSequenceOffset; - private final int fSequenceLength; - private final FileCharSequence fParent; - - public CharSubSequence(FileCharSequence parent, int offset, int length) { - fParent= parent; - fSequenceOffset= offset; - fSequenceLength= length; - } - - @Override - public int length() { - return fSequenceLength; - } - - @Override - public char charAt(int index) { - if (index < 0) { - throw new IndexOutOfBoundsException("index must be larger than 0"); //$NON-NLS-1$ - } - if (index >= fSequenceLength) { - throw new IndexOutOfBoundsException("index must be smaller than length"); //$NON-NLS-1$ - } - return fParent.charAt(fSequenceOffset + index); - } - - @Override - public CharSequence subSequence(int start, int end) { - if (end < start) { - throw new IndexOutOfBoundsException("end cannot be smaller than start"); //$NON-NLS-1$ - } - if (start < 0) { - throw new IndexOutOfBoundsException("start must be larger than 0"); //$NON-NLS-1$ - } - if (end > fSequenceLength) { - throw new IndexOutOfBoundsException("end must be smaller or equal than length"); //$NON-NLS-1$ - } - return fParent.subSequence(fSequenceOffset + start, fSequenceOffset + end); - } - - @Override - public String toString() { - try { - return fParent.getSubstring(fSequenceOffset, fSequenceLength); - } catch (IOException e) { - throw new FileCharSequenceException(e); - } catch (CoreException e) { - throw new FileCharSequenceException(e); - } - } - } - - - private static final class Buffer { - private final char[] fBuf; - private int fOffset; - private int fLength; - - private Buffer fNext; - private Buffer fPrevious; - - public Buffer() { - fBuf= new char[BUFFER_SIZE]; - reset(); - fNext= this; - fPrevious= this; - } - - public boolean contains(int pos) { - int offset= fOffset; - return offset <= pos && pos < offset + fLength; - } - - /** - * Fills the buffer by reading from the given reader. - * - * @param reader the reader to read from - * @param pos the offset of the reader in the file - * @return returns true if the end of the file has been reached - * @throws IOException if reading from the buffer fails - */ - public boolean fill(Reader reader, int pos) throws IOException { - int res= reader.read(fBuf); - if (res == -1) { - fOffset= pos; - fLength= 0; - return true; - } - - int charsRead= res; - while (charsRead < BUFFER_SIZE) { - res= reader.read(fBuf, charsRead, BUFFER_SIZE - charsRead); - if (res == -1) { - fOffset= pos; - fLength= charsRead; - return true; - } - charsRead+= res; - } - fOffset= pos; - fLength= BUFFER_SIZE; - return false; - } - - public char get(int pos) { - return fBuf[pos - fOffset]; - } - - public StringBuilder append(StringBuilder buf, int start, int length) { - return buf.append(fBuf, start - fOffset, length); - } - - public StringBuilder appendAll(StringBuilder buf) { - return buf.append(fBuf, 0, fLength); - } - - public int getEndOffset() { - return fOffset + fLength; - } - - public void removeFromChain() { - fPrevious.fNext= fNext; - fNext.fPrevious= fPrevious; - - fNext= this; - fPrevious= this; - } - - public void insertBefore(Buffer other) { - fNext= other; - fPrevious= other.fPrevious; - fPrevious.fNext= this; - other.fPrevious= this; - } - - public Buffer getNext() { - return fNext; - } - - public Buffer getPrevious() { - return fPrevious; - } - - public void reset() { - fOffset= -1; - fLength= 0; - } - } - - private final class FileCharSequence implements CharSequence { - - private static final String CHARSET_UTF_8= "UTF-8"; //$NON-NLS-1$ - - private Reader fReader; - private int fReaderPos; - - private Integer fLength; - - private Buffer fMostCurrentBuffer; // access to the buffer chain - private int fNumberOfBuffers; - - private IFile fFile; - - public FileCharSequence(IFile file) throws CoreException, IOException { - fNumberOfBuffers= 0; - reset(file); - } - - public void reset(IFile file) throws CoreException, IOException { - fFile= file; - fLength= null; // only calculated on demand - - Buffer curr= fMostCurrentBuffer; - if (curr != null) { - do { - curr.reset(); - curr= curr.getNext(); - } while (curr != fMostCurrentBuffer); - } - initializeReader(); - } - - private void initializeReader() throws CoreException, IOException { - if (fReader != null) { - fReader.close(); - } - String charset= fFile.getCharset(); - fReader= new InputStreamReader(getInputStream(charset), charset); - fReaderPos= 0; - } - - private InputStream getInputStream(String charset) throws CoreException, IOException { - boolean ok= false; - InputStream contents= fFile.getContents(); - try { - if (CHARSET_UTF_8.equals(charset)) { - /* - * This is a workaround for a corresponding bug in Java readers and writer, - * see http://developer.java.sun.com/developer/bugParade/bugs/4508058.html - * we remove the BOM before passing the stream to the reader - */ - IContentDescription description= fFile.getContentDescription(); - if ((description != null) && (description.getProperty(IContentDescription.BYTE_ORDER_MARK) != null)) { - int bomLength= IContentDescription.BOM_UTF_8.length; - byte[] bomStore= new byte[bomLength]; - int bytesRead= 0; - do { - int bytes= contents.read(bomStore, bytesRead, bomLength - bytesRead); - if (bytes == -1) { - throw new IOException(); - } - bytesRead += bytes; - } while (bytesRead < bomLength); - - if (!Arrays.equals(bomStore, IContentDescription.BOM_UTF_8)) { - // discard file reader, we were wrong, no BOM -> new stream - contents.close(); - contents= fFile.getContents(); - } - } - } - ok= true; - } finally { - if (!ok && contents != null) { - try { - contents.close(); - } catch (IOException ex) { - // ignore - } - } - } - return contents; - } - - private void clearReader() throws IOException { - if (fReader != null) { - fReader.close(); - } - fReader= null; - fReaderPos= Integer.MAX_VALUE; - } - - @Override - public int length() { - if (fLength == null) { - try { - getBuffer(Integer.MAX_VALUE); - } catch (IOException e) { - throw new FileCharSequenceException(e); - } catch (CoreException e) { - throw new FileCharSequenceException(e); - } - } - return fLength.intValue(); - } - - private Buffer getBuffer(int pos) throws IOException, CoreException { - Buffer curr= fMostCurrentBuffer; - if (curr != null) { - do { - if (curr.contains(pos)) { - return curr; - } - curr= curr.getNext(); - } while (curr != fMostCurrentBuffer); - } - - Buffer buf= findBufferToUse(); - fillBuffer(buf, pos); - if (buf.contains(pos)) { - return buf; - } - return null; - } - - private Buffer findBufferToUse() { - if (fNumberOfBuffers < NUMBER_OF_BUFFERS) { - fNumberOfBuffers++; - Buffer newBuffer= new Buffer(); - if (fMostCurrentBuffer == null) { - fMostCurrentBuffer= newBuffer; - return newBuffer; - } - newBuffer.insertBefore(fMostCurrentBuffer); // insert before first - return newBuffer; - } - return fMostCurrentBuffer.getPrevious(); - } - - private boolean fillBuffer(Buffer buffer, int pos) throws CoreException, IOException { - if (fReaderPos > pos) { - initializeReader(); - } - - do { - boolean endReached= buffer.fill(fReader, fReaderPos); - fReaderPos= buffer.getEndOffset(); - if (endReached) { - fLength= Integer.valueOf(fReaderPos); // at least we know the size of the file now - fReaderPos= Integer.MAX_VALUE; // will have to reset next time - return true; - } - } while (fReaderPos <= pos); - - return true; - } - - @Override - public char charAt(final int index) { - final Buffer current= fMostCurrentBuffer; - if (current != null && current.contains(index)) { - return current.get(index); - } - - if (index < 0) { - throw new IndexOutOfBoundsException("index must be larger than 0"); //$NON-NLS-1$ - } - if (fLength != null && index >= fLength.intValue()) { - throw new IndexOutOfBoundsException("index must be smaller than length"); //$NON-NLS-1$ - } - - try { - final Buffer buffer= getBuffer(index); - if (buffer == null) { - throw new IndexOutOfBoundsException("index must be smaller than length"); //$NON-NLS-1$ - } - if (buffer != fMostCurrentBuffer) { - // move to first - if (buffer.getNext() != fMostCurrentBuffer) { // already before the current? - buffer.removeFromChain(); - buffer.insertBefore(fMostCurrentBuffer); - } - fMostCurrentBuffer= buffer; - } - return buffer.get(index); - } catch (IOException e) { - throw new FileCharSequenceException(e); - } catch (CoreException e) { - throw new FileCharSequenceException(e); - } - } - - public String getSubstring(int start, int length) throws IOException, CoreException { - int pos= start; - int endPos= start + length; - - if (fLength != null && endPos > fLength.intValue()) { - throw new IndexOutOfBoundsException("end must be smaller than length"); //$NON-NLS-1$ - } - - StringBuilder res= new StringBuilder(length); - - Buffer buffer= getBuffer(pos); - while (pos < endPos && buffer != null) { - int bufEnd= buffer.getEndOffset(); - if (bufEnd >= endPos) { - return buffer.append(res, pos, endPos - pos).toString(); - } - buffer.append(res, pos, bufEnd - pos); - pos= bufEnd; - buffer= getBuffer(pos); - } - return res.toString(); - } - - - @Override - public CharSequence subSequence(int start, int end) { - if (end < start) { - throw new IndexOutOfBoundsException("end cannot be smaller than start"); //$NON-NLS-1$ - } - if (start < 0) { - throw new IndexOutOfBoundsException("start must be larger than 0"); //$NON-NLS-1$ - } - if (fLength != null && end > fLength.intValue()) { - throw new IndexOutOfBoundsException("end must be smaller than length"); //$NON-NLS-1$ - } - return new CharSubSequence(this, start, end - start); - } - - public void close() throws IOException { - clearReader(); - } - - @Override - public String toString() { - int len= fLength != null ? fLength.intValue() : 4000; - StringBuilder res= new StringBuilder(len); - try { - Buffer buffer= getBuffer(0); - while (buffer != null) { - buffer.appendAll(res); - buffer= getBuffer(res.length()); - } - return res.toString(); - } catch (IOException e) { - throw new FileCharSequenceException(e); - } catch (CoreException e) { - throw new FileCharSequenceException(e); - } - } - } - -} diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/FileNamePatternSearchScope.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/FileNamePatternSearchScope.java deleted file mode 100644 index 8b0b02d050..0000000000 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/FileNamePatternSearchScope.java +++ /dev/null @@ -1,184 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2010 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Originally copied from org.eclipse.search.internal.core.text.FileNamePatternSearchScope - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.ls.core.internal.search.text; - -import java.io.File; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IResourceProxy; -import org.eclipse.core.runtime.Assert; -import org.eclipse.core.runtime.IPath; - -public class FileNamePatternSearchScope extends TextSearchScope { - - /** - * Returns a scope for the given resources. - * @param description description of the scope - * @param resources the resources to be contained - * @param includeDerived specifies if derived resources are included or not - * @return a scope for the given resources. - */ - public static FileNamePatternSearchScope newSearchScope(String description, IResource[] resources, boolean includeDerived) { - return new FileNamePatternSearchScope(description, removeRedundantEntries(resources, includeDerived), includeDerived); - } - - private static final boolean IS_CASE_SENSITIVE_FILESYSTEM = !new File("Temp").equals(new File("temp")); //$NON-NLS-1$ //$NON-NLS-2$ - - private final String fDescription; - private final IResource[] fRootElements; - - private final Set fFileNamePatterns; - private Matcher fFileNameMatcher; - - private boolean fVisitDerived; - - private FileNamePatternSearchScope(String description, IResource[] resources, boolean visitDerived) { - Assert.isNotNull(description); - fDescription= description; - fRootElements= resources; - fFileNamePatterns= new HashSet<>(3); - fFileNameMatcher= null; - fVisitDerived= visitDerived; - } - - /** - * Returns the description of the scope - * @return the description of the scope - */ - public String getDescription() { - return fDescription; - } - - @Override - public IResource[] getRoots() { - return fRootElements; - } - - @Override - public boolean contains(IResourceProxy proxy) { - if (!fVisitDerived && proxy.isDerived()) { - return false; // all resources in a derived folder are considered to be derived, see bug 103576 - } - - if (proxy.getType() == IResource.FILE) { - return matchesFileName(proxy.getName()); - } - return true; - } - - /** - * Adds an file name pattern to the scope. - * - * @param pattern the pattern - */ - public void addFileNamePattern(String pattern) { - if (fFileNamePatterns.add(pattern)) { - fFileNameMatcher= null; // clear cache - } - } - - public void setFileNamePattern(Pattern pattern) { - fFileNameMatcher= pattern.matcher(""); //$NON-NLS-1$ - } - - - public Pattern getFileNamePattern() { - return getFileNameMatcher().pattern(); - } - - /** - * Returns if derived resources are included in the scope. - * - * @return if set derived resources are included in the scope. - */ - public boolean isIncludeDerived() { - return fVisitDerived; - } - - - private Matcher getFileNameMatcher() { - if (fFileNameMatcher == null) { - Pattern pattern; - if (fFileNamePatterns.isEmpty()) { - pattern= Pattern.compile(".*"); //$NON-NLS-1$ - } else { - String[] patternStrings= fFileNamePatterns.toArray(new String[fFileNamePatterns.size()]); - pattern= PatternConstructor.createPattern(patternStrings, IS_CASE_SENSITIVE_FILESYSTEM); - } - fFileNameMatcher= pattern.matcher(""); //$NON-NLS-1$ - } - return fFileNameMatcher; - } - - /** - * Tests if a file name matches to the file name patterns contained in the scope - * @param fileName The file name to test - * @return returns true if the file name is matching to a file name pattern - */ - private boolean matchesFileName(String fileName) { - return getFileNameMatcher().reset(fileName).matches(); - } - - /** - * Returns a description for the file name patterns in the scope - * @return the description of the scope - */ - public String getFileNamePatternDescription() { - String[] ext= fFileNamePatterns.toArray(new String[fFileNamePatterns.size()]); - Arrays.sort(ext); - StringBuilder buf= new StringBuilder(); - for (int i= 0; i < ext.length; i++) { - if (i > 0) { - buf.append(", "); //$NON-NLS-1$ - } - buf.append(ext[i]); - } - return buf.toString(); - } - - - private static IResource[] removeRedundantEntries(IResource[] elements, boolean includeDerived) { - ArrayList res= new ArrayList<>(); - for (IResource curr : elements) { - addToList(res, curr, includeDerived); - } - return res.toArray(new IResource[res.size()]); - } - - private static void addToList(ArrayList res, IResource curr, boolean includeDerived) { - if (!includeDerived && curr.isDerived(IResource.CHECK_ANCESTORS)) { - return; - } - IPath currPath= curr.getFullPath(); - for (int k= res.size() - 1; k >= 0 ; k--) { - IResource other= res.get(k); - IPath otherPath= other.getFullPath(); - if (otherPath.isPrefixOf(currPath)) { - return; - } - if (currPath.isPrefixOf(otherPath)) { - res.remove(k); - } - } - res.add(curr); - } - -} diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/FilesOfScopeCalculator.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/FilesOfScopeCalculator.java deleted file mode 100644 index 2f1d423f23..0000000000 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/FilesOfScopeCalculator.java +++ /dev/null @@ -1,66 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2008 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Originally copied from org.eclipse.search.internal.core.text.FilesOfScopeCalculator - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.ls.core.internal.search.text; - -import java.util.ArrayList; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IResourceProxy; -import org.eclipse.core.resources.IResourceProxyVisitor; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.MultiStatus; - -public class FilesOfScopeCalculator implements IResourceProxyVisitor { - - private final TextSearchScope fScope; - private final MultiStatus fStatus; - private ArrayList fFiles; - - public FilesOfScopeCalculator(TextSearchScope scope, MultiStatus status) { - fScope= scope; - fStatus= status; - } - - @Override - public boolean visit(IResourceProxy proxy) { - boolean inScope= fScope.contains(proxy); - - if (inScope && proxy.getType() == IResource.FILE) { - fFiles.add(proxy.requestResource()); - } - return inScope; - } - - public IFile[] process() { - fFiles= new ArrayList<>(); - try { - IResource[] roots= fScope.getRoots(); - for (IResource resource : roots) { - try { - if (resource.isAccessible()) { - resource.accept(this, 0); - } - } catch (CoreException ex) { - // report and ignore - fStatus.add(ex.getStatus()); - } - } - return fFiles.toArray(new IFile[fFiles.size()]); - } finally { - fFiles= null; - } - } -} diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/PatternConstructor.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/PatternConstructor.java deleted file mode 100644 index 9aba559ec1..0000000000 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/PatternConstructor.java +++ /dev/null @@ -1,514 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2013 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Originally copied from org.eclipse.search.internal.core.text.PatternConstructor - * - * Contributors: - * IBM Corporation - initial API and implementation - * Christian Walther (Indel AG) - Bug 402009: Disallow "whole word" together with regex - *******************************************************************************/ -package org.eclipse.jdt.ls.core.internal.search.text; - -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -import org.eclipse.core.runtime.Assert; -import org.eclipse.jface.text.FindReplaceDocumentAdapter; - -/** - * - */ -public class PatternConstructor { - - - private PatternConstructor() { - // don't instantiate - } - - public static Pattern createPattern(String pattern, boolean isCaseSensitive, boolean isRegex) throws PatternSyntaxException { - return createPattern(pattern, isRegex, true, isCaseSensitive, false); - } - - /** - * Creates a pattern element from the pattern string which is either a reg-ex expression or in - * our old 'StringMatcher' format. - * - * @param pattern The search pattern - * @param isRegex true if the passed string already is a reg-ex pattern - * @param isStringMatcher true if the passed string is in the StringMatcher format. - * @param isCaseSensitive Set to true to create a case insensitive pattern - * @param isWholeWord true to create a pattern that requires a word boundary at the - * beginning and the end. - * @return The created pattern - * @throws PatternSyntaxException if "\R" is at an illegal position - */ - public static Pattern createPattern(String pattern, boolean isRegex, boolean isStringMatcher, boolean isCaseSensitive, boolean isWholeWord) throws PatternSyntaxException { - if (isRegex) { - pattern= substituteLinebreak(pattern); - Assert.isTrue(!isWholeWord, "isWholeWord unsupported together with isRegex"); //$NON-NLS-1$ - } else { - int len= pattern.length(); - StringBuilder buffer= new StringBuilder(len + 10); - // don't add a word boundary if the search text does not start with - // a word char. (this works around a user input error). - if (isWholeWord && len > 0 && isWordChar(pattern.charAt(0))) { - buffer.append("\\b"); //$NON-NLS-1$ - } - appendAsRegEx(isStringMatcher, pattern, buffer); - if (isWholeWord && len > 0 && isWordChar(pattern.charAt(len - 1))) { - buffer.append("\\b"); //$NON-NLS-1$ - } - pattern= buffer.toString(); - } - - int regexOptions= Pattern.MULTILINE; - if (!isCaseSensitive) { - regexOptions|= Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE; - } - return Pattern.compile(pattern, regexOptions); - } - - /** - * Copied from {@link org.eclipse.jface.text.FindReplaceDocumentAdapter}' to support '\R' - * - * @param findString the string to substitute - * @return the new string - * @throws PatternSyntaxException if "\R" is at an illegal position - */ - private static String substituteLinebreak(String findString) throws PatternSyntaxException { - int length= findString.length(); - StringBuilder buf= new StringBuilder(length); - - int inCharGroup= 0; - int inBraces= 0; - boolean inQuote= false; - for (int i= 0; i < length; i++) { - char ch= findString.charAt(i); - switch (ch) { - case '[': - buf.append(ch); - if (! inQuote) { - inCharGroup++; - } - break; - - case ']': - buf.append(ch); - if (! inQuote) { - inCharGroup--; - } - break; - - case '{': - buf.append(ch); - if (! inQuote && inCharGroup == 0) { - inBraces++; - } - break; - - case '}': - buf.append(ch); - if (! inQuote && inCharGroup == 0) { - inBraces--; - } - break; - - case '\\': - if (i + 1 < length) { - char ch1= findString.charAt(i + 1); - if (inQuote) { - if (ch1 == 'E') { - inQuote= false; - } - buf.append(ch).append(ch1); - i++; - - } else if (ch1 == 'R') { - if (inCharGroup > 0 || inBraces > 0) { - String msg = "Illegal position for \\R"; - throw new PatternSyntaxException(msg, findString, i); - } - buf.append("(?>\\r\\n?|\\n)"); //$NON-NLS-1$ - i++; - - } else { - if (ch1 == 'Q') { - inQuote= true; - } - buf.append(ch).append(ch1); - i++; - } - } else { - buf.append(ch); - } - break; - - default: - buf.append(ch); - break; - } - - } - return buf.toString(); - } - - - private static boolean isWordChar(char c) { - return Character.isLetterOrDigit(c); - } - - /** - * Creates a pattern element from an array of patterns in the old 'StringMatcher' format. - * - * @param patterns The search patterns - * @param isCaseSensitive Set to true to create a case insensitive pattern - * @return The created pattern - * @throws PatternSyntaxException if "\R" is at an illegal position - */ - public static Pattern createPattern(String[] patterns, boolean isCaseSensitive) throws PatternSyntaxException { - StringBuilder pattern= new StringBuilder(); - for (int i= 0; i < patterns.length; i++) { - if (i > 0) { - // note that this works only as we know that the operands of the - // or expression will be simple and need no brackets. - pattern.append('|'); - } - appendAsRegEx(true, patterns[i], pattern); - } - return createPattern(pattern.toString(), true, true, isCaseSensitive, false); - } - - - public static StringBuilder appendAsRegEx(boolean isStringMatcher, String pattern, StringBuilder buffer) { - boolean isEscaped= false; - for (int i = 0; i < pattern.length(); i++) { - char c = pattern.charAt(i); - switch(c) { - // the backslash - case '\\': - // the backslash is escape char in string matcher - if (isStringMatcher && !isEscaped) { - isEscaped= true; - } - else { - buffer.append("\\\\"); //$NON-NLS-1$ - isEscaped= false; - } - break; - // characters that need to be escaped in the regex. - case '(': - case ')': - case '{': - case '}': - case '.': - case '[': - case ']': - case '$': - case '^': - case '+': - case '|': - if (isEscaped) { - buffer.append("\\\\"); //$NON-NLS-1$ - isEscaped= false; - } - buffer.append('\\'); - buffer.append(c); - break; - case '?': - if (isStringMatcher && !isEscaped) { - buffer.append('.'); - } - else { - buffer.append('\\'); - buffer.append(c); - isEscaped= false; - } - break; - case '*': - if (isStringMatcher && !isEscaped) { - buffer.append(".*"); //$NON-NLS-1$ - } - else { - buffer.append('\\'); - buffer.append(c); - isEscaped= false; - } - break; - default: - if (isEscaped) { - buffer.append("\\\\"); //$NON-NLS-1$ - isEscaped= false; - } - buffer.append(c); - break; - } - } - if (isEscaped) { - buffer.append("\\\\"); //$NON-NLS-1$ - isEscaped= false; - } - return buffer; - } - - /** - * Interprets escaped characters in the given replace pattern. - * - * @param replaceText the replace pattern - * @param foundText the found pattern to be replaced - * @param lineDelim the line delimiter to use for \R - * @return a replace pattern with escaped characters substituted by the respective characters - * @since 3.4 - */ - public static String interpretReplaceEscapes(String replaceText, String foundText, String lineDelim) { - return new ReplaceStringConstructor(lineDelim).interpretReplaceEscapes(replaceText, foundText); - } - - /** - * Copied from {@link FindReplaceDocumentAdapter}} - * - * FindReplaceDocumentAdapter with contributions from: - * Cagatay Calli - [find/replace] retain caps when replacing - https://bugs.eclipse.org/bugs/show_bug.cgi?id=28949 - * Cagatay Calli - [find/replace] define & fix behavior of retain caps with other escapes and text before \C - https://bugs.eclipse.org/bugs/show_bug.cgi?id=217061 - */ - private static class ReplaceStringConstructor { - - private static final int RC_MIXED= 0; - private static final int RC_UPPER= 1; - private static final int RC_LOWER= 2; - private static final int RC_FIRSTUPPER= 3; - - - private int fRetainCaseMode; - private final String fLineDelim; - - public ReplaceStringConstructor(String lineDelim) { - fLineDelim= lineDelim; - - } - - /** - * Interprets escaped characters in the given replace pattern. - * - * @param replaceText the replace pattern - * @param foundText the found pattern to be replaced - * @return a replace pattern with escaped characters substituted by the respective characters - * @since 3.4 - */ - private String interpretReplaceEscapes(String replaceText, String foundText) { - int length= replaceText.length(); - boolean inEscape= false; - StringBuilder buf= new StringBuilder(length); - - /* every string we did not check looks mixed at first - * so initialize retain case mode with RC_MIXED - */ - fRetainCaseMode= RC_MIXED; - - for (int i= 0; i < length; i++) { - final char ch= replaceText.charAt(i); - if (inEscape) { - i= interpretReplaceEscape(ch, i, buf, replaceText, foundText); - inEscape= false; - - } else if (ch == '\\') { - inEscape= true; - - } else if (ch == '$') { - buf.append(ch); - - /* - * Feature in java.util.regex.Matcher#replaceFirst(String): - * $00, $000, etc. are interpreted as $0 and - * $01, $001, etc. are interpreted as $1, etc. . - * If we support \0 as replacement pattern for capturing group 0, - * it would not be possible any more to write a replacement pattern - * that appends 0 to a capturing group (like $0\0). - * The fix is to interpret \00 and $00 as $0\0, and - * \01 and $01 as $0\1, etc. - */ - if (i + 2 < length) { - char ch1= replaceText.charAt(i + 1); - char ch2= replaceText.charAt(i + 2); - if (ch1 == '0' && '0' <= ch2 && ch2 <= '9') { - buf.append("0\\"); //$NON-NLS-1$ - i++; // consume the 0 - } - } - } else { - interpretRetainCase(buf, ch); - } - } - - if (inEscape) { - // '\' as last character is invalid, but we still add it to get an error message - buf.append('\\'); - } - return buf.toString(); - } - - /** - * Interprets the escaped character ch at offset i - * of the replaceText and appends the interpretation to buf. - * - * @param ch the escaped character - * @param i the offset - * @param buf the output buffer - * @param replaceText the original replace pattern - * @param foundText the found pattern to be replaced - * @return the new offset - * @since 3.4 - */ - private int interpretReplaceEscape(final char ch, int i, StringBuilder buf, String replaceText, String foundText) { - int length= replaceText.length(); - switch (ch) { - case 'r': - buf.append('\r'); - break; - case 'n': - buf.append('\n'); - break; - case 't': - buf.append('\t'); - break; - case 'f': - buf.append('\f'); - break; - case 'a': - buf.append('\u0007'); - break; - case 'e': - buf.append('\u001B'); - break; - case 'R': //see http://www.unicode.org/unicode/reports/tr18/#Line_Boundaries - buf.append(fLineDelim); - break; - /* - * \0 for octal is not supported in replace string, since it - * would conflict with capturing group \0, etc. - */ - case '0': - buf.append('$').append(ch); - /* - * See explanation in "Feature in java.util.regex.Matcher#replaceFirst(String)" - * in interpretReplaceEscape(String) above. - */ - if (i + 1 < length) { - char ch1= replaceText.charAt(i + 1); - if ('0' <= ch1 && ch1 <= '9') { - buf.append('\\'); - } - } - break; - - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - buf.append('$').append(ch); - break; - - case 'c': - if (i + 1 < length) { - char ch1= replaceText.charAt(i + 1); - interpretRetainCase(buf, (char)(ch1 ^ 64)); - i++; - } else { - String msg = "Illegal control escape sequence {0}"; - throw new PatternSyntaxException(msg, replaceText, i); - } - break; - - case 'x': - if (i + 2 < length) { - int parsedInt; - try { - parsedInt= Integer.parseInt(replaceText.substring(i + 1, i + 3), 16); - if (parsedInt < 0) { - throw new NumberFormatException(); - } - } catch (NumberFormatException e) { - String msg = "Illegal hexadecimal escape sequence {0}"; - throw new PatternSyntaxException(msg, replaceText, i); - } - interpretRetainCase(buf, (char) parsedInt); - i+= 2; - } else { - String msg = "Illegal hexadecimal escape sequence {0}"; - throw new PatternSyntaxException(msg, replaceText, i); - } - break; - - case 'u': - if (i + 4 < length) { - int parsedInt; - try { - parsedInt= Integer.parseInt(replaceText.substring(i + 1, i + 5), 16); - if (parsedInt < 0) { - throw new NumberFormatException(); - } - } catch (NumberFormatException e) { - String msg = "Illegal Unicode escape sequence {0}"; - throw new PatternSyntaxException(msg, replaceText, i); - } - interpretRetainCase(buf, (char) parsedInt); - i+= 4; - } else { - String msg = "Illegal Unicode escape sequence {0}"; - throw new PatternSyntaxException(msg, replaceText, i); - } - break; - - case 'C': - if(foundText.toUpperCase().equals(foundText)) { - fRetainCaseMode= RC_UPPER; - } else if (foundText.toLowerCase().equals(foundText)) { - fRetainCaseMode= RC_LOWER; - } else if(Character.isUpperCase(foundText.charAt(0))) { - fRetainCaseMode= RC_FIRSTUPPER; - } else { - fRetainCaseMode= RC_MIXED; - } - break; - - default: - // unknown escape k: append uninterpreted \k - buf.append('\\').append(ch); - break; - } - return i; - } - - /** - * Interprets current Retain Case mode (all upper-case,all lower-case,capitalized or mixed) - * and appends the character ch to buf after processing. - * - * @param buf the output buffer - * @param ch the character to process - * @since 3.4 - */ - private void interpretRetainCase(StringBuilder buf, char ch) { - if (fRetainCaseMode == RC_UPPER) { - buf.append(String.valueOf(ch).toUpperCase()); - } else if (fRetainCaseMode == RC_LOWER) { - buf.append(String.valueOf(ch).toLowerCase()); - } else if (fRetainCaseMode == RC_FIRSTUPPER) { - buf.append(String.valueOf(ch).toUpperCase()); - fRetainCaseMode= RC_MIXED; - } else { - buf.append(ch); - } - } - - } -} diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/TextSearchEngine.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/TextSearchEngine.java deleted file mode 100644 index 0358ba9c5e..0000000000 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/TextSearchEngine.java +++ /dev/null @@ -1,113 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2011 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Originally copied from org.eclipse.search.core.text.TextSearchEngine - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.ls.core.internal.search.text; - -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; - -/** - * A {@link TextSearchEngine} searches the content of a workspace file resources - * for matches to a given search pattern. - *

- * {@link #create()} gives access to an instance of the search engine. By default this is the default - * text search engine (see {@link #createDefault()}) but extensions can offer more sophisticated - * search engine implementations. - *

- * @since 3.2 - */ -public abstract class TextSearchEngine { - - /** - * Creates an instance of the search engine. By default this is the default text search engine (see {@link #createDefault()}), - * but extensions can offer more sophisticated search engine implementations. - * @return the created {@link TextSearchEngine}. - */ - public static TextSearchEngine create() { - return createDefault(); - //return SearchPlugin.getDefault().getTextSearchEngineRegistry().getPreferred(); - } - - /** - * Creates the default, built-in, text search engine that implements a brute-force search, not using - * any search index. - * Note that clients should always use the search engine provided by {@link #create()}. - * @return an instance of the default text search engine {@link TextSearchEngine}. - */ - public static TextSearchEngine createDefault() { - return new TextSearchEngine() { - @Override - public IStatus search(TextSearchScope scope, TextSearchRequestor requestor, Pattern searchPattern, IProgressMonitor monitor) { - return new TextSearchVisitor(requestor, searchPattern).search(scope, monitor); - } - - @Override - public IStatus search(IFile[] scope, TextSearchRequestor requestor, Pattern searchPattern, IProgressMonitor monitor) { - return new TextSearchVisitor(requestor, searchPattern).search(scope, monitor); - } - }; - } - - /** - * Uses a given search pattern to find matches in the content of workspace file resources. If a file is open in an editor, the - * editor buffer is searched. - - * @param requestor the search requestor that gets the search results - * @param scope the scope defining the resources to search in - * @param searchPattern The search pattern used to find matches in the file contents. - * @param monitor the progress monitor to use - * @return the status containing information about problems in resources searched. - */ - public abstract IStatus search(TextSearchScope scope, TextSearchRequestor requestor, Pattern searchPattern, IProgressMonitor monitor); - - /** - * Uses a given search pattern to find matches in the content of workspace file resources. If a file is open in an editor, the - * editor buffer is searched. - - * @param requestor the search requestor that gets the search results - * @param scope the files to search in - * @param searchPattern The search pattern used to find matches in the file contents. - * @param monitor the progress monitor to use - * @return the status containing information about problems in resources searched. - */ - public abstract IStatus search(IFile[] scope, TextSearchRequestor requestor, Pattern searchPattern, IProgressMonitor monitor); - - - /** - * Creates a pattern for the given search string and the given options. - * - * @param pattern the search pattern. If isRegex is: - *
    - *
  • false: a string including '*' and '?' wildcards and '\' for - * escaping the literals '*', '?' and '\'
  • - *
  • true: a regex as specified by {@link Pattern} plus "\R" denoting - * a line delimiter (platform independent)
  • - *
- * @param isRegex true if the given string follows the {@link Pattern} including - * "\R" - * @param isCaseSensitive Set to true to create a case insensitive pattern - * @return the created pattern - * @throws PatternSyntaxException if "\R" is at an illegal position - * @see Pattern - * @since 3.8 - */ - public static Pattern createPattern(String pattern, boolean isCaseSensitive, boolean isRegex) throws PatternSyntaxException { - return PatternConstructor.createPattern(pattern, isRegex, true, isCaseSensitive, false); - } - -} diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/TextSearchMatchAccess.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/TextSearchMatchAccess.java deleted file mode 100644 index c7efe0e8fd..0000000000 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/TextSearchMatchAccess.java +++ /dev/null @@ -1,85 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2008 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Originally copied from org.eclipse.search.core.text.TextSearchMatchAccess - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ - -package org.eclipse.jdt.ls.core.internal.search.text; - -import org.eclipse.core.resources.IFile; - -/** - * A {@link TextSearchMatchAccess} gives access to a pattern match found by the {@link TextSearchEngine}. - *

- * Please note that {@link TextSearchMatchAccess} objects do not - * have value semantic. The state of the object might change over - * time especially since objects are reused for different call backs. Clients shall not keep a reference to - * a {@link TextSearchMatchAccess} element. - *

- *

- * This class should only be implemented by implementors of a {@link TextSearchEngine}. - *

- * @since 3.2 - */ -public abstract class TextSearchMatchAccess { - - /** - * Returns the file the match was found in. - * - * @return the file the match was found. - */ - public abstract IFile getFile(); - - /** - * Returns the offset of this search match. - * - * @return the offset of this search match - */ - public abstract int getMatchOffset(); - - /** - * Returns the length of this search match. - * - * @return the length of this search match - */ - public abstract int getMatchLength(); - - /** - * Returns the length of this file's content. - * - * @return the length of this file's content. - */ - public abstract int getFileContentLength(); - - /** - * Returns a character of the file's content at the given offset - * - * @param offset the offset - * @return the character at the given offset - * @throws IndexOutOfBoundsException an {@link IndexOutOfBoundsException} is - * thrown when the offset is negative or not less than the file content's length. - */ - public abstract char getFileContentChar(int offset); - - /** - * Returns the file's content at the given offsets. - * - * @param offset the offset of the requested content - * @param length the of the requested content - * @return the substring of the file's content - * @throws IndexOutOfBoundsException an {@link IndexOutOfBoundsException} is - * thrown when the offset or the length are negative - * or when offset + length is not less than the file content's length. - */ - public abstract String getFileContent(int offset, int length); - -} diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/TextSearchRequestor.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/TextSearchRequestor.java deleted file mode 100644 index 14539350fc..0000000000 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/TextSearchRequestor.java +++ /dev/null @@ -1,162 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2015 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Originally copied from org.eclipse.search.core.text.TextSearchRequestor - * - * Contributors: - * IBM Corporation - initial API and implementation - * Terry Parker (Google Inc.) - Bug 441016 - Speed up text search by parallelizing it using JobGroups - *******************************************************************************/ - -package org.eclipse.jdt.ls.core.internal.search.text; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.runtime.CoreException; - -/** - * Collects the results from a search engine query. - * Clients implement a subclass to pass to {@link TextSearchEngine#search(TextSearchScope, - * TextSearchRequestor, java.util.regex.Pattern, org.eclipse.core.runtime.IProgressMonitor)} - * and implement the {@link #acceptPatternMatch(TextSearchMatchAccess)} - * method, and possibly override other life cycle methods. - *

- * The search engine calls {@link #beginReporting()} when a search starts, - * then calls {@link #acceptFile(IFile)} for a file visited. - * If {@link #acceptFile(IFile)} returns true {@link #reportBinaryFile(IFile)} is - * called if the file could be binary followed by - * {@link #acceptPatternMatch(TextSearchMatchAccess)} for each pattern match found - * in this file. The end of the search is signaled with a call to {@link #endReporting()}. - * Note that {@link #acceptFile(IFile)} is called for all files in the search scope, - * even if no match can be found. - *

- *

- * {@link TextSearchEngine#search(TextSearchScope, TextSearchRequestor, java.util.regex.Pattern, - * org.eclipse.core.runtime.IProgressMonitor)} can perform parallel processing. - * To support parallel processing, subclasses of this class must synchronize access - * to any shared data accumulated by or accessed by overrides of the {@link #acceptFile(IFile)}, - * {@link #reportBinaryFile(IFile)} and {@link #acceptPatternMatch(TextSearchMatchAccess)} - * methods, and override the {@link #canRunInParallel()} method to return true. - *

- *

- * The order of the search results is unspecified and may vary from request to request; - * when displaying results, clients should not rely on the order but should instead arrange the results - * in an order that would be more meaningful to the user. - *

- * - * @see TextSearchEngine - * @since 3.2 - */ -public abstract class TextSearchRequestor { - - /** - * Notification sent before starting the search action. - * Typically, this would tell a search requestor to clear previously - * recorded search results. - *

- * The default implementation of this method does nothing. Subclasses - * may override. - *

- */ - public void beginReporting() { - // do nothing - } - - /** - * Notification sent after having completed the search action. - * Typically, this would tell a search requestor collector that no more - * results will be forthcoming in this search. - *

- * The default implementation of this method does nothing. Subclasses - * may override. - *

- */ - public void endReporting() { - // do nothing - } - - /** - * Notification sent before search starts in the given file. This method is called for all files that are contained - * in the search scope. - * Implementors can decide if the file content should be searched for search matches or not. - *

- * The default behaviour is to search the file for matches. - *

- *

- * If {@link #canRunInParallel()} returns true, this method may be called in parallel by different threads, - * so any access or updates to collections of results or other shared state must be synchronized. - *

- * @param file the file resource to be searched. - * @return If false, no pattern matches will be reported for the content of this file. - * @throws CoreException implementors can throw a {@link CoreException} if accessing the resource fails or another - * problem prevented the processing of the search match. - */ - public boolean acceptFile(IFile file) throws CoreException { - return true; - } - - /** - * Notification sent that a file might contain binary context. - * It is the choice of the search engine to report binary files and it is the heuristic of the search engine to decide - * that a file could be binary. - * Implementors can decide if the file content should be searched for search matches or not. - *

- * This call is sent after calls {link {@link #acceptFile(IFile)} that return true and before any matches - * reported for this file with {@link #acceptPatternMatch(TextSearchMatchAccess)}. - *

- *

- * If {@link #canRunInParallel()} returns true, this method may be called in parallel by different threads, - * so any access or updates to collections of results or other shared state must be synchronized. - *

- *

- * The default behaviour is to skip binary files - *

- * - * @param file the file that might be binary - * @return If false, no pattern matches will be reported for the content of this file. - */ - public boolean reportBinaryFile(IFile file) { - return false; - } - - /** - * Accepts the given search match and decides if the search should continue for this file. - *

- * If {@link #canRunInParallel()} returns true, this method may be called in parallel by different threads, - * so any access or updates to collections of results or other shared state must be synchronized. - *

- * - * @param matchAccess gives access to information of the match found. The matchAccess is not a value - * object. Its value might change after this method is finished, and the element might be reused. - * @return If false is returned no further matches will be reported for this file. - * @throws CoreException implementors can throw a {@link CoreException} if accessing the resource fails or another - * problem prevented the processing of the search match. - */ - public boolean acceptPatternMatch(TextSearchMatchAccess matchAccess) throws CoreException { - return true; - } - - /** - * Reports whether this TextSearchRequestor supports executing the text search algorithm - * in parallel. - *

- * Subclasses should override this method and return true if they desire faster search results - * and their {@link #acceptFile(IFile)}, {@link #reportBinaryFile(IFile)} and - * {@link #acceptPatternMatch(TextSearchMatchAccess)} methods are thread-safe. - *

- *

- * The default behavior is to not use parallelism when running a text search. - *

- * - * @return If true, the text search will be run in parallel. - * @since 3.10 - */ - public boolean canRunInParallel() { - return false; - } -} diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/TextSearchScope.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/TextSearchScope.java deleted file mode 100644 index 94112f2af0..0000000000 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/TextSearchScope.java +++ /dev/null @@ -1,87 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2008 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Originally copied from org.eclipse.search.core.text.TextSearchScope - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ - -package org.eclipse.jdt.ls.core.internal.search.text; - -import java.util.regex.Pattern; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IResourceProxy; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.MultiStatus; - -/** - * A {@link TextSearchScope} defines the scope of a search. The scope consists of all workbench resources that are accepted - * by {@link #contains(IResourceProxy)} and that either are a root element ({@link #getRoots()}) or have a root element - * in their parent chain. - * - * @see #newSearchScope(IResource[], java.util.regex.Pattern, boolean) - * @since 3.2 - */ -public abstract class TextSearchScope { - - - /** - * Creates a scope that consists of all files that match the fileNamePattern and that - * either are one of the roots, or have one of the roots in their parent chain. - * If visitDerivedResources is not enabled, all files that are marked derived or - * have a derived container in their parent chain are not part of the scope. - * - * @param rootResources the resources that are the roots of the scope - * @param fileNamePattern file name pattern for this scope. - * @param visitDerivedResources if set also derived folders and files are searched. - * @return a scope the search scope - */ - public static TextSearchScope newSearchScope(IResource[] rootResources, Pattern fileNamePattern, boolean visitDerivedResources) { - FileNamePatternSearchScope scope= FileNamePatternSearchScope.newSearchScope("", rootResources, visitDerivedResources); //$NON-NLS-1$ - scope.setFileNamePattern(fileNamePattern); - return scope; - } - - - /** - * Returns the resources that form the root. Roots can not contain each other. Root elements are only part of the - * scope if they are also accepted by {@link #contains(IResourceProxy)}. - * - * @return returns the set of root resources. The default behavior is to return the workspace root. - */ - public IResource[] getRoots() { - return new IResource[] { ResourcesPlugin.getWorkspace().getRoot() }; - } - - /** - * Returns if a given resource is part of the scope. If a container is not part of the scope, also all its members - * are not part of the scope. - * - * @param proxy the resource proxy to test. - * @return returns true if a resource is part of the scope. if false is returned the resource - * and all its children are not part of the scope. - */ - public abstract boolean contains(IResourceProxy proxy); - - - /** - * Evaluates all files in this scope. - * - * @param status a {@link MultiStatus} to collect the error status that occurred while collecting resources. - * @return returns the files in the scope. - */ - public IFile[] evaluateFilesInScope(MultiStatus status) { - return new FilesOfScopeCalculator(this, status).process(); - } - - -} diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/TextSearchVisitor.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/TextSearchVisitor.java deleted file mode 100644 index b7d4bafe09..0000000000 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/search/text/TextSearchVisitor.java +++ /dev/null @@ -1,558 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2018 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Originally copied from org.eclipse.search.internal.core.text.TextSearchVisitor - * - * Contributors: - * IBM Corporation - initial API and implementation - * Terry Parker (Google Inc.) - Bug 441016 - Speed up text search by parallelizing it using JobGroups - * Sergey Prigogin (Google) - Bug 489551 - File Search silently drops results on StackOverflowError - *******************************************************************************/ -package org.eclipse.jdt.ls.core.internal.search.text; - -import java.io.CharConversionException; -import java.io.IOException; -import java.nio.charset.IllegalCharsetNameException; -import java.nio.charset.UnsupportedCharsetException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.eclipse.core.filebuffers.FileBuffers; -import org.eclipse.core.filebuffers.ITextFileBuffer; -import org.eclipse.core.filebuffers.ITextFileBufferManager; -import org.eclipse.core.filebuffers.LocationKind; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IResourceStatus; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.MultiStatus; -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.core.runtime.OperationCanceledException; -import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.SubMonitor; -import org.eclipse.core.runtime.content.IContentDescription; -import org.eclipse.core.runtime.content.IContentType; -import org.eclipse.core.runtime.content.IContentTypeManager; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.core.runtime.jobs.JobGroup; -import org.eclipse.jdt.ls.core.internal.IConstants; -import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; -import org.eclipse.jdt.ls.core.internal.Messages; -import org.eclipse.jdt.ls.core.internal.search.text.FileCharSequenceProvider.FileCharSequenceException; -import org.eclipse.jface.text.IDocument; - -/** - * The visitor that does the actual work. - */ -public class TextSearchVisitor { - - public static final boolean TRACING= "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.search/perf")); //$NON-NLS-1$ //$NON-NLS-2$ - private static final int NUMBER_OF_LOGICAL_THREADS= Runtime.getRuntime().availableProcessors(); - private static final int FILES_PER_JOB= 50; - private static final int MAX_JOBS_COUNT= 100; - - public static class ReusableMatchAccess extends TextSearchMatchAccess { - - private int fOffset; - private int fLength; - private IFile fFile; - private CharSequence fContent; - - public void initialize(IFile file, int offset, int length, CharSequence content) { - fFile= file; - fOffset= offset; - fLength= length; - fContent= content; - } - - @Override - public IFile getFile() { - return fFile; - } - - @Override - public int getMatchOffset() { - return fOffset; - } - - @Override - public int getMatchLength() { - return fLength; - } - - @Override - public int getFileContentLength() { - return fContent.length(); - } - - @Override - public char getFileContentChar(int offset) { - return fContent.charAt(offset); - } - - @Override - public String getFileContent(int offset, int length) { - return fContent.subSequence(offset, offset + length).toString(); // must pass a copy! - } - } - - /** - * A JobGroup for text searches across multiple files. - */ - private static class TextSearchJobGroup extends JobGroup { - public TextSearchJobGroup(String name, int maxThreads, int initialJobCount) { - super(name, maxThreads, initialJobCount); - } - - // Always continue processing all other files, even if errors are encountered in individual files. - @Override - protected boolean shouldCancel(IStatus lastCompletedJobResult, int numberOfFailedJobs, int numberOfCancelledJobs) { - return false; - } - } - - /** - * A job to find matches in a set of files. - */ - private class TextSearchJob extends Job { - private final IFile[] fFiles; - private final int fBegin; - private final int fEnd; - private final Map fDocumentsInEditors; - private FileCharSequenceProvider fileCharSequenceProvider; - - private IPath previousLocationFromFile; - // occurences need to be passed to FileSearchResultCollector with growing offset - private List occurencesForPreviousLocation; - private CharSequence charsequenceForPreviousLocation; - - - /** - * Searches for matches in a set of files. - * - * @param files an array of IFiles, a portion of which is to be processed - * @param begin the first element in the file array to process - * @param end one past the last element in the array to process - * @param documentsInEditors a map from IFile to IDocument for all open, dirty editors - */ - public TextSearchJob(IFile[] files, int begin, int end, Map documentsInEditors) { - super(files[begin].getName()); - setSystem(true); - fFiles= files; - fBegin= begin; - fEnd= end; - fDocumentsInEditors= documentsInEditors; - } - - @Override - protected IStatus run(IProgressMonitor inner) { - MultiStatus multiStatus= - new MultiStatus(IConstants.PLUGIN_ID, IStatus.OK, "Problems encountered during text search.", null); - SubMonitor subMonitor= SubMonitor.convert(inner, fEnd - fBegin); - this.fileCharSequenceProvider= new FileCharSequenceProvider(); - for (int i= fBegin; i < fEnd && !fFatalError; i++) { - IStatus status= processFile(fFiles[i], subMonitor.split(1)); - // Only accumulate interesting status - if (!status.isOK()) - { - multiStatus.add(status); - // Group cancellation is propagated to this job's monitor. - // Stop processing and return the status for the completed jobs. - } - } - if (charsequenceForPreviousLocation != null) { - try { - fileCharSequenceProvider.releaseCharSequence(charsequenceForPreviousLocation); - } catch (IOException e) { - JavaLanguageServerPlugin.logException(e.getMessage(), e); - } finally { - charsequenceForPreviousLocation= null; - } - } - fileCharSequenceProvider= null; - previousLocationFromFile= null; - occurencesForPreviousLocation= null; - return multiStatus; - } - - public IStatus processFile(IFile file, IProgressMonitor monitor) { - // A natural cleanup after the change to use JobGroups is accepted would be to move these - // methods to the TextSearchJob class. - Matcher matcher= fSearchPattern.pattern().length() == 0 ? null : fSearchPattern.matcher(""); //$NON-NLS-1$ - - try { - if (!fCollector.acceptFile(file) || matcher == null) { - return Status.OK_STATUS; - } - - IDocument document= getOpenDocument(file, getDocumentsInEditors()); - if (document != null) { - DocumentCharSequence documentCharSequence= new DocumentCharSequence(document); - // assume all documents are non-binary - locateMatches(file, documentCharSequence, matcher, monitor); - } else if (previousLocationFromFile != null && previousLocationFromFile.equals(file.getLocation()) && !occurencesForPreviousLocation.isEmpty()) { - // reuse previous result - ReusableMatchAccess matchAccess= new ReusableMatchAccess(); - for (TextSearchMatchAccess occurence : occurencesForPreviousLocation) { - matchAccess.initialize(file, occurence.getMatchOffset(), occurence.getMatchLength(), charsequenceForPreviousLocation); - boolean goOn= fCollector.acceptPatternMatch(matchAccess); - if (!goOn) { - break; - } - } - } else { - if (charsequenceForPreviousLocation != null) { - try { - fileCharSequenceProvider.releaseCharSequence(charsequenceForPreviousLocation); - charsequenceForPreviousLocation= null; - } catch (IOException e) { - JavaLanguageServerPlugin.logException(e.getMessage(), e); - } - } - try { - charsequenceForPreviousLocation= fileCharSequenceProvider.newCharSequence(file); - if (hasBinaryContent(charsequenceForPreviousLocation, file) && !fCollector.reportBinaryFile(file)) { - occurencesForPreviousLocation= Collections.emptyList(); - return Status.OK_STATUS; - } - occurencesForPreviousLocation= locateMatches(file, charsequenceForPreviousLocation, matcher, monitor); - previousLocationFromFile= file.getLocation(); - } catch (FileCharSequenceProvider.FileCharSequenceException e) { - e.throwWrappedException(); - } - } - } catch (UnsupportedCharsetException e) { - String[] args= { getCharSetName(file), file.getFullPath().makeRelative().toString()}; - String message= Messages.format("File ''{1}'' has been skipped: Unsupported encoding ''{0}''", args); - return new Status(IStatus.ERROR, IConstants.PLUGIN_ID, IStatus.ERROR, message, e); - } catch (IllegalCharsetNameException e) { - String[] args= { getCharSetName(file), file.getFullPath().makeRelative().toString()}; - String message= Messages.format("File ''{1}'' has been skipped: Illegal encoding ''{0}''.", args); - return new Status(IStatus.ERROR, IConstants.PLUGIN_ID, IStatus.ERROR, message, e); - } catch (IOException e) { - String[] args= { getExceptionMessage(e), file.getFullPath().makeRelative().toString()}; - String message= Messages.format("File ''{1}'' has been skipped, problem while reading: (''{0}'')", args); - return new Status(IStatus.ERROR, IConstants.PLUGIN_ID, IStatus.ERROR, message, e); - } catch (CoreException e) { - if (fIsLightweightAutoRefresh && IResourceStatus.RESOURCE_NOT_FOUND == e.getStatus().getCode()) { - return monitor.isCanceled() ? Status.CANCEL_STATUS : Status.OK_STATUS; - } - String[] args= { getExceptionMessage(e), file.getFullPath().makeRelative().toString() }; - String message = Messages.format("File ''{1}'' has been skipped, problem while reading: (''{0}'')", args); - return new Status(IStatus.ERROR, IConstants.PLUGIN_ID, IStatus.ERROR, message, e); - } catch (StackOverflowError e) { - fFatalError= true; - String message = "Search pattern is too complex. Search canceled."; - return new Status(IStatus.ERROR, IConstants.PLUGIN_ID, IStatus.ERROR, message, e); - } finally { - synchronized (fLock) { - fCurrentFile= file; - fNumberOfScannedFiles++; - } - } - return Status.OK_STATUS; - } - - public Map getDocumentsInEditors() { - return fDocumentsInEditors; - } - - } - - - private final TextSearchRequestor fCollector; - private final Pattern fSearchPattern; - - private IProgressMonitor fProgressMonitor; - - private int fNumberOfFilesToScan; - private int fNumberOfScannedFiles; // Protected by fLock - private IFile fCurrentFile; // Protected by fLock - private Object fLock= new Object(); - - private final MultiStatus fStatus; - private volatile boolean fFatalError; // If true, terminates the search. - - private boolean fIsLightweightAutoRefresh; - - public TextSearchVisitor(TextSearchRequestor collector, Pattern searchPattern) { - fCollector= collector; - fStatus = new MultiStatus(IConstants.PLUGIN_ID, IStatus.OK, "Problems encountered during text search.", null); - - fSearchPattern= searchPattern; - - fIsLightweightAutoRefresh= Platform.getPreferencesService().getBoolean(ResourcesPlugin.PI_RESOURCES, ResourcesPlugin.PREF_LIGHTWEIGHT_AUTO_REFRESH, false, null); - } - - public IStatus search(IFile[] files, IProgressMonitor monitor) { - if (files.length == 0) { - return fStatus; - } - fProgressMonitor= monitor == null ? new NullProgressMonitor() : monitor; - fNumberOfScannedFiles= 0; - fNumberOfFilesToScan= files.length; - fCurrentFile= null; - int maxThreads= fCollector.canRunInParallel() ? NUMBER_OF_LOGICAL_THREADS : 1; - int jobCount= 1; - if (maxThreads > 1) { - jobCount= (files.length + FILES_PER_JOB - 1) / FILES_PER_JOB; - } - // Too many job references can cause OOM, see bug 514961 - if (jobCount > MAX_JOBS_COUNT) { - jobCount= MAX_JOBS_COUNT; - } - final JobGroup jobGroup= new TextSearchJobGroup("Text Search", maxThreads, jobCount); //$NON-NLS-1$ - long startTime= TRACING ? System.currentTimeMillis() : 0; - - Job monitorUpdateJob = new Job("Search progress polling") { - private int fLastNumberOfScannedFiles= 0; - - @Override - public IStatus run(IProgressMonitor inner) { - while (!inner.isCanceled()) { - // Propagate user cancellation to the JobGroup. - if (fProgressMonitor.isCanceled()) { - jobGroup.cancel(); - break; - } - - IFile file; - int numberOfScannedFiles; - synchronized (fLock) { - file= fCurrentFile; - numberOfScannedFiles= fNumberOfScannedFiles; - } - if (file != null) { - String fileName= file.getName(); - Object[] args= { fileName, Integer.valueOf(numberOfScannedFiles), Integer.valueOf(fNumberOfFilesToScan)}; - fProgressMonitor.subTask(Messages.format("Scanning file {1} of {2}: {0}", args)); - int steps= numberOfScannedFiles - fLastNumberOfScannedFiles; - fProgressMonitor.worked(steps); - fLastNumberOfScannedFiles += steps; - } - try { - Thread.sleep(100); - } catch (InterruptedException e) { - return Status.OK_STATUS; - } - } - return Status.OK_STATUS; - } - }; - - try { - String taskName= fSearchPattern.pattern().length() == 0 - ? "Searching for files..." - : Messages.format("Searching for pattern ''{0}''...", fSearchPattern.pattern()); - fProgressMonitor.beginTask(taskName, fNumberOfFilesToScan); - monitorUpdateJob.setSystem(true); - monitorUpdateJob.schedule(); - try { - fCollector.beginReporting(); - Map documentsInEditors = Collections.emptyMap(); - int filesPerJob = Math.max(1, files.length / jobCount); - IFile[] filesByLocation= new IFile[files.length]; - System.arraycopy(files, 0, filesByLocation, 0, files.length); - // Sorting files to search by location allows to more easily reuse - // search results from one file to the other when they have same location - Arrays.sort(filesByLocation, (o1, o2) -> { - if (o1 == o2) { - return 0; - } - if (o1.getLocation() == o2.getLocation()) { - return 0; - } - if (o1.getLocation() == null) { - return +1; - } - if (o2.getLocation() == null) { - return -1; - } - return o1.getLocation().toString().compareTo(o2.getLocation().toString()); - }); - for (int first= 0; first < filesByLocation.length; first += filesPerJob) { - int end= Math.min(filesByLocation.length, first + filesPerJob); - Job job= new TextSearchJob(filesByLocation, first, end, documentsInEditors); - job.setJobGroup(jobGroup); - job.schedule(); - } - - // The monitorUpdateJob is managing progress and cancellation, - // so it is ok to pass a null monitor into the job group. - jobGroup.join(0, null); - if (fProgressMonitor.isCanceled()) { - throw new OperationCanceledException("Operation Canceled"); - } - - fStatus.addAll(jobGroup.getResult()); - return fStatus; - } catch (InterruptedException e) { - throw new OperationCanceledException("Operation Canceled"); - } finally { - monitorUpdateJob.cancel(); - } - } finally { - fProgressMonitor.done(); - fCollector.endReporting(); - if (TRACING) { - Object[] args= { Integer.valueOf(fNumberOfScannedFiles), Integer.valueOf(jobCount), Integer.valueOf(NUMBER_OF_LOGICAL_THREADS), Long.valueOf(System.currentTimeMillis() - startTime) }; - System.out.println(Messages.format( - "[TextSearch] Search duration for {0} files in {1} jobs using {2} threads: {3}ms", args)); //$NON-NLS-1$ - } - } - } - - public IStatus search(TextSearchScope scope, IProgressMonitor monitor) { - return search(scope.evaluateFilesInScope(fStatus), monitor); - } - - /** - * Returns a map from IFile to IDocument for all open, dirty editors. After creation this map - * is not modified, so returning a non-synchronized map is ok. - * - * @return a map from IFile to IDocument for all open, dirty editors - */ - // private Map evalNonFileBufferDocuments() { - // Map result= new HashMap<>(); - // IWorkbench workbench= SearchPlugin.getDefault().getWorkbench(); - // IWorkbenchWindow[] windows= workbench.getWorkbenchWindows(); - // for (IWorkbenchWindow window : windows) { - // IWorkbenchPage[] pages= window.getPages(); - // for (IWorkbenchPage page : pages) { - // IEditorReference[] editorRefs= page.getEditorReferences(); - // for (IEditorReference editorRef : editorRefs) { - // IEditorPart ep= editorRef.getEditor(false); - // if (ep instanceof ITextEditor && ep.isDirty()) { // only dirty editors - // evaluateTextEditor(result, ep); - // } - // } - // } - // } - // return result; - // } - - // private void evaluateTextEditor(Map result, IEditorPart ep) { - // IEditorInput input= ep.getEditorInput(); - // if (input instanceof IFileEditorInput) { - // IFile file= ((IFileEditorInput) input).getFile(); - // if (!result.containsKey(file)) { // take the first editor found - // ITextFileBufferManager bufferManager= FileBuffers.getTextFileBufferManager(); - // ITextFileBuffer textFileBuffer= bufferManager.getTextFileBuffer(file.getFullPath(), LocationKind.IFILE); - // if (textFileBuffer != null) { - // // file buffer has precedence - // result.put(file, textFileBuffer.getDocument()); - // } else { - // // use document provider - // IDocument document= ((ITextEditor) ep).getDocumentProvider().getDocument(input); - // if (document != null) { - // result.put(file, document); - // } - // } - // } - // } - // } - - private boolean hasBinaryContent(CharSequence seq, IFile file) throws CoreException { - IContentDescription desc= file.getContentDescription(); - if (desc != null) { - IContentType contentType= desc.getContentType(); - if (contentType != null && contentType.isKindOf(Platform.getContentTypeManager().getContentType(IContentTypeManager.CT_TEXT))) { - return false; - } - } - - // avoid calling seq.length() at it runs through the complete file, - // thus it would do so for all binary files. - try { - int limit= FileCharSequenceProvider.BUFFER_SIZE; - for (int i= 0; i < limit; i++) { - if (seq.charAt(i) == '\0') { - return true; - } - } - } catch (IndexOutOfBoundsException e) { - } catch (FileCharSequenceException ex) { - if (ex.getCause() instanceof CharConversionException) { - return true; - } - throw ex; - } - return false; - } - - private List locateMatches(IFile file, CharSequence searchInput, Matcher matcher, IProgressMonitor monitor) throws CoreException { - List occurences= null; - matcher.reset(searchInput); - int k= 0; - while (matcher.find()) { - if (occurences == null) { - occurences= new ArrayList<>(); - } - int start= matcher.start(); - int end= matcher.end(); - if (end != start) { // don't report 0-length matches - ReusableMatchAccess access= new ReusableMatchAccess(); - access.initialize(file, start, end - start, searchInput); - occurences.add(access); - boolean res= fCollector.acceptPatternMatch(access); - if (!res) { - return occurences; // no further reporting requested - } - } - // Periodically check for cancellation and quit working on the current file if the job has been cancelled. - if (++k % 20 == 0 && monitor.isCanceled()) { - break; - } - } - if (occurences == null) { - occurences= Collections.emptyList(); - } - return occurences; - } - - - private String getExceptionMessage(Exception e) { - String message= e.getLocalizedMessage(); - if (message == null) { - return e.getClass().getName(); - } - return message; - } - - private IDocument getOpenDocument(IFile file, Map documentsInEditors) { - IDocument document= documentsInEditors.get(file); - if (document == null) { - ITextFileBufferManager bufferManager= FileBuffers.getTextFileBufferManager(); - ITextFileBuffer textFileBuffer= bufferManager.getTextFileBuffer(file.getFullPath(), LocationKind.IFILE); - if (textFileBuffer != null) { - document= textFileBuffer.getDocument(); - } - } - return document; - } - - private String getCharSetName(IFile file) { - try { - return file.getCharset(); - } catch (CoreException e) { - return "unknown"; //$NON-NLS-1$ - } - } - -} -