Merge remote-tracking branch 'origin/master'

This commit is contained in:
Anton Makeev
2016-06-25 14:43:39 +02:00
9 changed files with 290 additions and 275 deletions
@@ -22,8 +22,9 @@ import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
public class NameEnvironment extends UserDataHolderBase {
public static final int OBJECT_NAME = IndexTree.hashIdentifier("Object");
public final QualifiedName empty;
public final QualifiedName java_lang_Object;
public final QualifiedName java_lang;
public final QualifiedName java_lang_Enum;
public final QualifiedName[] annotation;
public final NamesEnumerator myNamesEnumerator;
@@ -31,7 +32,7 @@ public class NameEnvironment extends UserDataHolderBase {
public NameEnvironment() {
myNamesEnumerator = new NamesEnumerator();
empty = myNamesEnumerator.getFullName(new int[]{}, true);
java_lang_Object = fromString("java.lang.Object", true);
java_lang = fromString("java.lang", true);
java_lang_Enum = fromString("java.lang.Enum", true);
annotation = new QualifiedName[]{fromString("java.lang.annotation.Annotation", true)};
}
@@ -57,13 +58,6 @@ public class NameEnvironment extends UserDataHolderBase {
return ids[ids.length - 1];
}
public QualifiedName qualifiedName(Symbol owner, int shortName) {
if (shortName == NamesEnumerator.NO_NAME || owner == null || owner.myQualifiedName == null) {
return null;
}
return qualifiedName(owner.myQualifiedName, shortName, true);
}
public QualifiedName qualifiedName(QualifiedName prefix, int shortName, boolean create) {
if (shortName == NamesEnumerator.NO_NAME)
return null;
@@ -176,7 +176,7 @@ public class SingleClassHierarchy extends ClassHierarchy {
// compacting
result = Arrays.copyOf(result, i);
Arrays.sort(result, Comparator.comparing(a -> a.myFileId));
Arrays.sort(result, (a1, a2) -> Integer.compare(a1.myFileId, a2.myFileId));
return result;
}
@@ -17,6 +17,7 @@ package com.intellij.psi.stubsHierarchy.impl;
import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree;
import com.intellij.psi.stubsHierarchy.stubs.*;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
@@ -38,47 +39,51 @@ public class StubEnter {
void unitEnter(Unit tree) {
PackageSymbol pkg = tree.myPackageId != null ? mySymbols.enterPackage(tree.myPackageId) : mySymbols.myRootPackage;
enter(tree.myClasses, tree.myUnitInfo, pkg);
enter(tree.myClasses, tree.myUnitInfo, pkg, pkg.myQualifiedName);
}
private void enter(ClassDeclaration[] trees, UnitInfo info, Symbol owner) {
private void enter(ClassDeclaration[] trees, UnitInfo info, Symbol owner, @Nullable QualifiedName ownerName) {
for (ClassDeclaration tree : trees) {
enter(tree, info, owner);
enter(tree, info, owner, ownerName);
}
}
private ClassSymbol[] enter(Declaration[] trees, UnitInfo info, Symbol owner) {
private ClassSymbol[] enter(Declaration[] trees, UnitInfo info, Symbol owner, @Nullable QualifiedName ownerName) {
ClassSymbol[] members = new ClassSymbol[trees.length];
int i = 0;
for (Declaration tree : trees) {
ClassSymbol member = enter(tree, info, owner);
ClassSymbol member = enter(tree, info, owner, ownerName);
if (member != null && member.myShortName != 0) {
members[i++] = member;
}
}
members = members.length == 0 ? ClassSymbol.EMPTY_ARRAY : Arrays.copyOf(members, i);
if (i == 0) return ClassSymbol.EMPTY_ARRAY;
if (i < members.length) {
members = Arrays.copyOf(members, i);
}
Arrays.sort(members, CLASS_SYMBOL_BY_NAME_COMPARATOR);
return members;
}
private ClassSymbol enter(Declaration tree, UnitInfo info, Symbol owner) {
private ClassSymbol enter(Declaration tree, UnitInfo info, Symbol owner, QualifiedName ownerName) {
if (tree instanceof ClassDeclaration) {
return classEnter((ClassDeclaration)tree, info, owner);
return classEnter((ClassDeclaration)tree, info, owner, ownerName);
}
if (tree instanceof MemberDeclaration) {
memberEnter((MemberDeclaration)tree, info, owner);
memberEnter((MemberDeclaration)tree, info, owner, ownerName);
return null;
}
return null;
}
private void memberEnter(MemberDeclaration tree, UnitInfo info, Symbol owner) {
private void memberEnter(MemberDeclaration tree, UnitInfo info, Symbol owner, @Nullable QualifiedName ownerName) {
MemberSymbol mc = new MemberSymbol(owner);
ClassSymbol[] members = enter(tree.myDeclarations, info, mc);
ClassSymbol[] members = enter(tree.myDeclarations, info, mc, ownerName);
mc.setMembers(members);
}
private ClassSymbol classEnter(ClassDeclaration tree, UnitInfo info, Symbol owner) {
private ClassSymbol classEnter(ClassDeclaration tree, UnitInfo info, Symbol owner, @Nullable QualifiedName ownerName) {
int flags = checkFlags(tree.mods, owner);
if (info.getType() == IndexTree.BYTECODE) {
flags |= IndexTree.COMPILED;
@@ -88,13 +93,17 @@ public class StubEnter {
supers = myNameEnvironment.annotation;
}
ClassSymbol classSymbol = mySymbols.enterClass(tree.myClassAnchor, flags, tree.myName, owner, info, supers);
int name = tree.myName;
QualifiedName qname = name == NamesEnumerator.NO_NAME || ownerName == null ? null
: myNameEnvironment.qualifiedName(ownerName, name, true);
ClassSymbol classSymbol = mySymbols.enterClass(tree.myClassAnchor, flags, name, owner, info, supers, qname);
if (uncompleted != null) {
if (uncompleted != null) {
uncompleted.add(classSymbol);
}
ClassSymbol[] members = enter(tree.myDeclarations, info, classSymbol);
classSymbol.setMembers(members);
if (tree.myDeclarations.length > 0) {
classSymbol.setMembers(enter(tree.myDeclarations, info, classSymbol, qname));
}
return classSymbol;
}
@@ -29,6 +29,23 @@ public class StubHierarchyConnector {
myResolve = new StubResolver(symbols, this);
}
private void resolveName(Symbol.ClassSymbol place, QualifiedName name, Set<Symbol.ClassSymbol> result) throws IncompleteHierarchyException {
if (place.isCompiled()) {
Symbol.ClassSymbol[] candidates = myResolve.findGlobalType(name);
if (candidates.length == 0) {
throw new IncompleteHierarchyException();
}
Collections.addAll(result, candidates);
} else {
for (Symbol symbol : myResolve.resolveBase(place, name.myComponents)) {
if (symbol instanceof Symbol.ClassSymbol) {
result.add((Symbol.ClassSymbol)symbol);
}
}
}
}
void connect(Symbol sym) {
Symbol.ClassSymbol c = (Symbol.ClassSymbol) sym;
@@ -36,45 +53,40 @@ public class StubHierarchyConnector {
((Symbol.ClassSymbol)c.myOwner).connect(this);
}
Object supers = c.mySuperClasses;
if (supers == null) {
c.setSupers(Collections.emptySet());
return;
}
// Determine supertype.
Set<Symbol> supertypes = new HashSet<Symbol>();
for (QualifiedName name : c.mySuperNames) {
if (c.isCompiled()) {
if (name != null) {
Collections.addAll(supertypes, myResolve.findGlobalType(name));
Set<Symbol.ClassSymbol> supertypes = new HashSet<>();
try {
if (supers instanceof QualifiedName[]) {
for (QualifiedName name : (QualifiedName[])supers) {
resolveName(c, name, supertypes);
}
} else {
try {
supertypes.addAll(myResolve.resolveBase(c, name.myComponents));
}
catch (IncompleteHierarchyException ignore) {
c.markHierarchyIncomplete();
break;
}
resolveName(c, (QualifiedName)supers, supertypes);
}
}
if (c.myQualifiedName == myNameEnvironment.java_lang_Object || c.isHierarchyIncomplete()) {
c.mySuperClasses = Symbol.ClassSymbol.EMPTY_ARRAY;
} else {
for (Iterator<Symbol> iter = supertypes.iterator(); iter.hasNext();) {
Symbol s = iter.next();
if (!(s instanceof Symbol.ClassSymbol) || s.myQualifiedName == myNameEnvironment.java_lang_Object) {
iter.remove();
}
}
if (supertypes.isEmpty()) {
c.mySuperClasses = Symbol.ClassSymbol.EMPTY_ARRAY;
}
else {
//noinspection SuspiciousToArrayCall
c.mySuperClasses = supertypes.toArray(new Symbol.ClassSymbol[supertypes.size()]);
}
catch (IncompleteHierarchyException ignore) {
c.markHierarchyIncomplete();
return;
}
// cleaning up
c.mySuperNames = null;
c.myUnitInfo = null;
for (Iterator<Symbol.ClassSymbol> iterator = supertypes.iterator(); iterator.hasNext();) {
if (isJavaLangObject(iterator.next())) {
iterator.remove();
}
}
c.setSupers(supertypes);
}
private boolean isJavaLangObject(Symbol s) {
return s.myShortName == NameEnvironment.OBJECT_NAME &&
s.myOwner instanceof Symbol.PackageSymbol &&
((Symbol.PackageSymbol)s.myOwner).myQualifiedName == myNameEnvironment.java_lang;
}
}
@@ -103,35 +103,11 @@ public class StubResolver {
if (!processed.add(s)) {
return;
}
findImmediateMemberType(s, name, symbols);
processMembers(s.getMembers(), name, symbols, false);
if (s.isClass())
findInheritedMemberType((Symbol.ClassSymbol)s, name, symbols, processed);
}
private static void findImmediateMemberType(Symbol s, int name, Set<Symbol> symbols) {
Symbol.ClassSymbol[] members = s.members();
int index = getIndex(name, members);
if (index < 0) return;
// elem
Symbol.ClassSymbol member = members[index];
symbols.add(member);
// on the left
int i = index - 1;
while (i >= 0 && members[i].myShortName == name) {
member = members[i];
symbols.add(member);
i--;
}
// on the right
i = index + 1;
while (i < members.length && members[i].myShortName == name) {
member = members[i];
symbols.add(member);
i++;
}
}
private void findInheritedMemberType(Symbol.ClassSymbol c, int name, Set<Symbol> symbols, Set<Symbol> processed)
throws IncompleteHierarchyException {
for (Symbol.ClassSymbol st : c.getSuperClasses(myConnector))
@@ -204,25 +180,25 @@ public class StubResolver {
return;
for (Symbol.ClassSymbol c : cs.getSuperClasses(myConnector))
importFrom(c);
importMember(cs.members(), name, symbols, true);
processMembers(cs.getMembers(), name, symbols, true);
}
}.importFrom(tsym);
}
private static void importMember(Symbol.ClassSymbol[] members, int name, Set<Symbol> symbols, boolean isStatic) {
private static void processMembers(Symbol.ClassSymbol[] members, int name, Set<Symbol> symbols, boolean requireStatic) {
int index = getIndex(name, members);
if (index < 0) return;
// elem
Symbol.ClassSymbol member = members[index];
if (!isStatic || member.isStatic()) {
if (!requireStatic || member.isStatic()) {
symbols.add(member);
}
// on the left
int i = index - 1;
while (i >= 0 && members[i].myShortName == name) {
member = members[i];
if (!isStatic || member.isStatic()) {
if (!requireStatic || member.isStatic()) {
symbols.add(member);
}
i--;
@@ -231,7 +207,7 @@ public class StubResolver {
i = index + 1;
while (i < members.length && members[i].myShortName == name) {
member = members[i];
if (!isStatic || member.isStatic()) {
if (!requireStatic || member.isStatic()) {
symbols.add(member);
}
i++;
@@ -21,7 +21,9 @@ import com.intellij.util.BitUtil;
import gnu.trove.TIntHashSet;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.Comparator;
import java.util.Set;
/**
* Java symbols needed for hierarchy building. Mostly classes ({@link ClassSymbol}) or packages ({@link PackageSymbol}),
@@ -30,13 +32,11 @@ import java.util.Comparator;
public abstract class Symbol {
public int myFlags;
public int myShortName;
public final QualifiedName myQualifiedName;
public final Symbol myOwner;
public Symbol(int flags, Symbol owner, QualifiedName qualifiedName, int name) {
public Symbol(int flags, Symbol owner, int name) {
this.myFlags = flags;
this.myOwner = owner;
this.myQualifiedName = qualifiedName;
this.myShortName = name;
}
@@ -45,13 +45,10 @@ public abstract class Symbol {
return myShortName;
}
public ClassSymbol[] members() {
ClassSymbol[] getMembers() {
return ClassSymbol.EMPTY_ARRAY;
}
public void setMembers(ClassSymbol[] members) {
}
public boolean isStatic() {
return BitUtil.isSet(myFlags, IndexTree.STATIC);
}
@@ -77,35 +74,40 @@ public abstract class Symbol {
}
public static class PackageSymbol extends Symbol {
final QualifiedName myQualifiedName;
public PackageSymbol(Symbol owner, QualifiedName fullname, int name) {
super(IndexTree.PACKAGE, owner, fullname, name);
setMembers(ClassSymbol.EMPTY_ARRAY);
super(IndexTree.PACKAGE, owner, name);
myQualifiedName = fullname;
}
}
/** A class for class symbols
*/
public static class ClassSymbol extends Symbol {
public static class ClassSymbol extends MemberSymbol {
private static final int HIERARCHY_INCOMPLETE = 1 << 20;
private static final int CONNECT_STARTED = 1 << 21;
public static final ClassSymbol[] EMPTY_ARRAY = new ClassSymbol[0];
final StubClassAnchor myClassAnchor;
ClassSymbol[] mySuperClasses;
/**
* null for empty 'supers' list
* ClassSymbol/QualifiedName for a single resolved/unresolved super
* ClassSymbol[]/QualifiedName[] for multiple resolved/unresolved supers
*/
Object mySuperClasses;
UnitInfo myUnitInfo;
QualifiedName[] mySuperNames;
private ClassSymbol[] myMembers;
ClassSymbol(StubClassAnchor classAnchor,
int flags,
Symbol owner,
QualifiedName fullname,
int name,
UnitInfo unitInfo,
QualifiedName[] supers) {
super(flags | IndexTree.CLASS, owner, fullname, name);
int flags,
Symbol owner,
int name,
UnitInfo unitInfo,
QualifiedName[] supers) {
super(flags | IndexTree.CLASS, owner, name);
this.myClassAnchor = classAnchor;
this.mySuperNames = supers;
this.mySuperClasses = supers.length == 0 ? null : supers.length == 1 ? supers[0] : supers;
this.myUnitInfo = unitInfo;
}
@@ -137,28 +139,27 @@ public abstract class Symbol {
@NotNull
ClassSymbol[] rawSuperClasses() {
assert isConnectStarted();
return mySuperClasses == null ? EMPTY_ARRAY : mySuperClasses;
return mySuperClasses instanceof ClassSymbol ? new ClassSymbol[]{(ClassSymbol)mySuperClasses} :
mySuperClasses instanceof ClassSymbol[] ? (ClassSymbol[])mySuperClasses :
EMPTY_ARRAY;
}
boolean isCompiled() {
return BitUtil.isSet(myFlags, IndexTree.COMPILED);
}
public ClassSymbol[] members() {
return myMembers;
}
public void setMembers(ClassSymbol[] members) {
this.myMembers = members;
}
void markHierarchyIncomplete() {
mySuperClasses = EMPTY_ARRAY;
mySuperNames = null;
myUnitInfo = null;
setSupers(Collections.emptySet());
myFlags = BitUtil.set(myFlags, HIERARCHY_INCOMPLETE, true);
}
void setSupers(Set<ClassSymbol> supers) {
mySuperClasses = supers.isEmpty() ? null :
supers.size() == 1 ? supers.iterator().next() :
supers.toArray(new ClassSymbol[supers.size()]);
myUnitInfo = null;
}
boolean isHierarchyIncomplete() {
return BitUtil.isSet(myFlags, HIERARCHY_INCOMPLETE);
}
@@ -182,15 +183,27 @@ public abstract class Symbol {
* Represents methods, fields and other constructs that may contain anonymous or local classes.
*/
public static class MemberSymbol extends Symbol {
private ClassSymbol[] myMembers;
public MemberSymbol(Symbol owner) {
super(IndexTree.MEMBER, owner, null, NamesEnumerator.NO_NAME);
/**
* null when no members, or a single ClassSymbol, or ClassSymbol[]
*/
private Object myMembers = null;
MemberSymbol(Symbol owner) {
super(IndexTree.MEMBER, owner, NamesEnumerator.NO_NAME);
}
public ClassSymbol[] members() {
return myMembers;
MemberSymbol(int flags, Symbol owner, int name) {
super(flags, owner, name);
}
public void setMembers(ClassSymbol[] members) {
this.myMembers = members;
ClassSymbol[] getMembers() {
return myMembers == null ? ClassSymbol.EMPTY_ARRAY :
myMembers instanceof ClassSymbol ? new ClassSymbol[]{(ClassSymbol)myMembers} :
(ClassSymbol[])myMembers;
}
void setMembers(ClassSymbol[] members) {
myMembers = members.length == 0 ? null : members.length == 1 ? members[0] : members;
}
}
@@ -63,21 +63,23 @@ public class Symbols {
return (ClassSymbol[])cs;
}
public ClassSymbol enterClass(ClassAnchor classAnchor, int flags, int shortName, Symbol owner, UnitInfo info, QualifiedName[] supers) {
QualifiedName qualifiedName = myNameEnvironment.qualifiedName(owner, shortName);
public ClassSymbol enterClass(ClassAnchor classAnchor,
int flags,
int shortName,
Symbol owner,
UnitInfo info,
QualifiedName[] supers,
@Nullable QualifiedName qualifiedName) {
StubClassAnchor stubClassAnchor = new StubClassAnchor(myClassSymbols.size(), classAnchor);
ClassSymbol c = new ClassSymbol(stubClassAnchor, flags, owner, qualifiedName, shortName, info, supers);
ClassSymbol c = new ClassSymbol(stubClassAnchor, flags, owner, shortName, info, supers);
myClassSymbols.add(c);
putClassByName(c);
if (qualifiedName != null) {
putClassByName(c, qualifiedName.myId);
}
return c;
}
private void putClassByName(ClassSymbol classSymbol) {
QualifiedName name = classSymbol.myQualifiedName;
// anonymous class
if (name == null)
return;
int nameId = name.myId;
private void putClassByName(ClassSymbol classSymbol, int nameId) {
ensureByNameCapacity(nameId);
Object cs = myClassSymbolsByNameId[nameId];
if (cs == null) {
@@ -43,7 +43,7 @@ public class IndexTree {
public static final byte JAVA = 1;
public static final byte GROOVY = 2;
private static int hashIdentifier(@Nullable String s) {
public static int hashIdentifier(@Nullable String s) {
if (s == null) return 0;
// not using String.hashCode because this way there's less collisions for short package names like 'com'
@@ -536,175 +536,184 @@ public class FindManagerImpl extends FindManager {
int offset,
@NotNull FindModel model,
@NotNull final VirtualFile file) {
FileType ftype = file.getFileType();
Language lang = null;
if (ftype instanceof LanguageFileType) {
lang = ((LanguageFileType)ftype).getLanguage();
}
CommentsLiteralsSearchData data = model.getUserData(ourCommentsLiteralsSearchDataKey);
if (data == null || !Comparing.equal(data.lastFile, file) || !data.model.equals(model)) {
SyntaxHighlighter highlighter = getHighlighter(file, lang);
if (highlighter == null) {
// no syntax highlighter -> no search
return NOT_FOUND_RESULT;
synchronized (model) {
FileType ftype = file.getFileType();
Language lang = null;
if (ftype instanceof LanguageFileType) {
lang = ((LanguageFileType)ftype).getLanguage();
}
TokenSet tokensOfInterest = TokenSet.EMPTY;
Set<Language> relevantLanguages;
if (lang != null) {
final Language finalLang = lang;
relevantLanguages = ApplicationManager.getApplication().runReadAction(new Computable<Set<Language>>() {
@Override
public Set<Language> compute() {
THashSet<Language> result = new THashSet<Language>();
CommentsLiteralsSearchData data = model.getUserData(ourCommentsLiteralsSearchDataKey);
if (data == null || !Comparing.equal(data.lastFile, file) || !data.model.equals(model)) {
SyntaxHighlighter highlighter = getHighlighter(file, lang);
FileViewProvider viewProvider = PsiManager.getInstance(myProject).findViewProvider(file);
if (viewProvider != null) {
result.addAll(viewProvider.getLanguages());
}
if (result.isEmpty()) {
result.add(finalLang);
}
return result;
}
});
for (Language relevantLanguage:relevantLanguages) {
tokensOfInterest = addTokenTypesForLanguage(model, relevantLanguage, tokensOfInterest);
if (highlighter == null) {
// no syntax highlighter -> no search
return NOT_FOUND_RESULT;
}
if(model.isInStringLiteralsOnly()) {
// TODO: xml does not have string literals defined so we add XmlAttributeValue element type as convenience
final Lexer xmlLexer = getHighlighter(null, Language.findLanguageByID("XML")).getHighlightingLexer();
final String marker = "xxx";
xmlLexer.start("<a href=\"" + marker+ "\" />");
TokenSet tokensOfInterest = TokenSet.EMPTY;
Set<Language> relevantLanguages;
if (lang != null) {
final Language finalLang = lang;
relevantLanguages = ApplicationManager.getApplication().runReadAction(new Computable<Set<Language>>() {
@Override
public Set<Language> compute() {
THashSet<Language> result = new THashSet<Language>();
while (!marker.equals(xmlLexer.getTokenText())) {
xmlLexer.advance();
if (xmlLexer.getTokenType() == null) break;
FileViewProvider viewProvider = PsiManager.getInstance(myProject).findViewProvider(file);
if (viewProvider != null) {
result.addAll(viewProvider.getLanguages());
}
if (result.isEmpty()) {
result.add(finalLang);
}
return result;
}
});
for (Language relevantLanguage : relevantLanguages) {
tokensOfInterest = addTokenTypesForLanguage(model, relevantLanguage, tokensOfInterest);
}
IElementType convenienceXmlAttrType = xmlLexer.getTokenType();
if (convenienceXmlAttrType != null) {
tokensOfInterest = TokenSet.orSet(tokensOfInterest, TokenSet.create(convenienceXmlAttrType));
}
}
} else {
relevantLanguages = ContainerUtil.newHashSet();
if (ftype instanceof AbstractFileType) {
if (model.isInCommentsOnly()) {
tokensOfInterest = TokenSet.create(CustomHighlighterTokenType.LINE_COMMENT, CustomHighlighterTokenType.MULTI_LINE_COMMENT);
}
if (model.isInStringLiteralsOnly()) {
tokensOfInterest = TokenSet.orSet(tokensOfInterest, TokenSet.create(CustomHighlighterTokenType.STRING, CustomHighlighterTokenType.SINGLE_QUOTED_STRING));
// TODO: xml does not have string literals defined so we add XmlAttributeValue element type as convenience
final Lexer xmlLexer = getHighlighter(null, Language.findLanguageByID("XML")).getHighlightingLexer();
final String marker = "xxx";
xmlLexer.start("<a href=\"" + marker + "\" />");
while (!marker.equals(xmlLexer.getTokenText())) {
xmlLexer.advance();
if (xmlLexer.getTokenType() == null) break;
}
IElementType convenienceXmlAttrType = xmlLexer.getTokenType();
if (convenienceXmlAttrType != null) {
tokensOfInterest = TokenSet.orSet(tokensOfInterest, TokenSet.create(convenienceXmlAttrType));
}
}
}
else {
relevantLanguages = ContainerUtil.newHashSet();
if (ftype instanceof AbstractFileType) {
if (model.isInCommentsOnly()) {
tokensOfInterest = TokenSet.create(CustomHighlighterTokenType.LINE_COMMENT, CustomHighlighterTokenType.MULTI_LINE_COMMENT);
}
if (model.isInStringLiteralsOnly()) {
tokensOfInterest = TokenSet.orSet(tokensOfInterest, TokenSet
.create(CustomHighlighterTokenType.STRING, CustomHighlighterTokenType.SINGLE_QUOTED_STRING));
}
}
}
Matcher matcher = model.isRegularExpressions() ? compileRegExp(model, "") : null;
StringSearcher searcher = matcher != null ? null : new StringSearcher(model.getStringToFind(), model.isCaseSensitive(), true);
SyntaxHighlighterOverEditorHighlighter highlighterAdapter =
new SyntaxHighlighterOverEditorHighlighter(highlighter, file, myProject);
data =
new CommentsLiteralsSearchData(file, relevantLanguages, highlighterAdapter, tokensOfInterest, searcher, matcher, model.clone());
data.highlighter.restart(text);
model.putUserData(ourCommentsLiteralsSearchDataKey, data);
}
Matcher matcher = model.isRegularExpressions() ? compileRegExp(model, ""):null;
StringSearcher searcher = matcher != null ? null: new StringSearcher(model.getStringToFind(), model.isCaseSensitive(), true);
SyntaxHighlighterOverEditorHighlighter highlighterAdapter = new SyntaxHighlighterOverEditorHighlighter(highlighter, file, myProject);
data = new CommentsLiteralsSearchData(file, relevantLanguages, highlighterAdapter, tokensOfInterest, searcher, matcher, model.clone());
data.highlighter.restart(text);
model.putUserData(ourCommentsLiteralsSearchDataKey, data);
}
int initialStartOffset = model.isForward() && data.startOffset < offset ? data.startOffset : 0;
data.highlighter.resetPosition(initialStartOffset);
final Lexer lexer = data.highlighter.getHighlightingLexer();
int initialStartOffset = model.isForward() && data.startOffset < offset ? data.startOffset : 0;
data.highlighter.resetPosition(initialStartOffset);
final Lexer lexer = data.highlighter.getHighlightingLexer();
IElementType tokenType;
TokenSet tokens = data.tokensOfInterest;
IElementType tokenType;
TokenSet tokens = data.tokensOfInterest;
int lastGoodOffset = 0;
boolean scanningForward = model.isForward();
FindResultImpl prevFindResult = NOT_FOUND_RESULT;
int lastGoodOffset = 0;
boolean scanningForward = model.isForward();
FindResultImpl prevFindResult = NOT_FOUND_RESULT;
while ((tokenType = lexer.getTokenType()) != null) {
if (lexer.getState() == 0) lastGoodOffset = lexer.getTokenStart();
while((tokenType = lexer.getTokenType()) != null) {
if (lexer.getState() == 0) lastGoodOffset = lexer.getTokenStart();
final TextAttributesKey[] keys = data.highlighter.getTokenHighlights(tokenType);
final TextAttributesKey[] keys = data.highlighter.getTokenHighlights(tokenType);
if (tokens.contains(tokenType) ||
(model.isInStringLiteralsOnly() && ChunkExtractor.isHighlightedAsString(keys)) ||
(model.isInCommentsOnly() && ChunkExtractor.isHighlightedAsComment(keys))
) {
int start = lexer.getTokenStart();
int end = lexer.getTokenEnd();
if (model.isInStringLiteralsOnly()) { // skip literal quotes itself from matching
char c = text.charAt(start);
if (c == '"' || c == '\'') {
while (start < end && c == text.charAt(start)) {
++start;
if (c == text.charAt(end - 1) && start < end) --end;
if (tokens.contains(tokenType) ||
(model.isInStringLiteralsOnly() && ChunkExtractor.isHighlightedAsString(keys)) ||
(model.isInCommentsOnly() && ChunkExtractor.isHighlightedAsComment(keys))
) {
int start = lexer.getTokenStart();
int end = lexer.getTokenEnd();
if (model.isInStringLiteralsOnly()) { // skip literal quotes itself from matching
char c = text.charAt(start);
if (c == '"' || c == '\'') {
while (start < end && c == text.charAt(start)) {
++start;
if (c == text.charAt(end - 1) && start < end) --end;
}
}
}
}
while(true) {
FindResultImpl findResult = null;
while (true) {
FindResultImpl findResult = null;
if (data.searcher != null) {
int matchStart = data.searcher.scan(text, textArray, start, end);
if (data.searcher != null) {
int matchStart = data.searcher.scan(text, textArray, start, end);
if (matchStart != -1 && matchStart >= start) {
final int matchEnd = matchStart + model.getStringToFind().length();
if (matchStart >= offset || !scanningForward)
findResult = new FindResultImpl(matchStart, matchEnd);
else {
start = matchEnd;
continue;
}
}
} else if (start <= end) {
data.matcher.reset(StringPattern.newBombedCharSequence(text.subSequence(start, end)));
if (data.matcher.find()) {
final int matchEnd = start + data.matcher.end();
int matchStart = start + data.matcher.start();
if (matchStart >= offset || !scanningForward) {
findResult = new FindResultImpl(matchStart, matchEnd);
}
else {
int diff = 0;
if (start == end) {
diff = scanningForward ? 1:-1;
if (matchStart != -1 && matchStart >= start) {
final int matchEnd = matchStart + model.getStringToFind().length();
if (matchStart >= offset || !scanningForward)
findResult = new FindResultImpl(matchStart, matchEnd);
else {
start = matchEnd;
continue;
}
start = matchEnd + diff;
}
}
else if (start <= end) {
data.matcher.reset(StringPattern.newBombedCharSequence(text.subSequence(start, end)));
if (data.matcher.find()) {
final int matchEnd = start + data.matcher.end();
int matchStart = start + data.matcher.start();
if (matchStart >= offset || !scanningForward) {
findResult = new FindResultImpl(matchStart, matchEnd);
}
else {
int diff = 0;
if (start == end) {
diff = scanningForward ? 1 : -1;
}
start = matchEnd + diff;
continue;
}
}
}
if (findResult != null) {
if (scanningForward) {
data.startOffset = lastGoodOffset;
return findResult;
}
else {
if (findResult.getEndOffset() >= offset) return prevFindResult;
prevFindResult = findResult;
start = findResult.getEndOffset();
continue;
}
}
break;
}
if (findResult != null) {
if (scanningForward) {
data.startOffset = lastGoodOffset;
return findResult;
} else {
if (findResult.getEndOffset() >= offset) return prevFindResult;
prevFindResult = findResult;
start = findResult.getEndOffset();
continue;
}
}
else {
Language tokenLang = tokenType.getLanguage();
if (tokenLang != lang && tokenLang != Language.ANY && !data.relevantLanguages.contains(tokenLang)) {
tokens = addTokenTypesForLanguage(model, tokenLang, tokens);
data.tokensOfInterest = tokens;
data.relevantLanguages.add(tokenLang);
}
break;
}
} else {
Language tokenLang = tokenType.getLanguage();
if (tokenLang != lang && tokenLang != Language.ANY && !data.relevantLanguages.contains(tokenLang)) {
tokens = addTokenTypesForLanguage(model, tokenLang, tokens);
data.tokensOfInterest = tokens;
data.relevantLanguages.add(tokenLang);
}
lexer.advance();
}
lexer.advance();
return prevFindResult;
}
return prevFindResult;
}
private static TokenSet addTokenTypesForLanguage(FindModel model, Language lang, TokenSet tokensOfInterest) {