diff --git a/java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerHierarchyInfoImpl.java b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerHierarchyInfoImpl.java new file mode 100644 index 000000000000..a9138c6d4161 --- /dev/null +++ b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerHierarchyInfoImpl.java @@ -0,0 +1,62 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.compiler.backwardRefs; + +import com.intellij.compiler.CompilerDirectHierarchyInfo; +import com.intellij.openapi.util.Couple; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiElement; +import com.intellij.psi.search.GlobalSearchScope; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; +import java.util.stream.Stream; + +class CompilerHierarchyInfoImpl implements CompilerDirectHierarchyInfo { + private final GlobalSearchScope myDirtyScope; + private final GlobalSearchScope mySearchScope; + private Couple> myCandidatePerFile; + + CompilerHierarchyInfoImpl(Couple> candidatePerFile, + GlobalSearchScope dirtyScope, + GlobalSearchScope searchScope) { + myCandidatePerFile = candidatePerFile; + myDirtyScope = dirtyScope; + mySearchScope = searchScope; + } + + @Override + @NotNull + public Stream getHierarchyChildren() { + return selectClassesInScope(myCandidatePerFile.getFirst(), mySearchScope); + } + + @Override + @NotNull + public Stream getHierarchyChildCandidates() { + return selectClassesInScope(myCandidatePerFile.getSecond(), mySearchScope); + } + + @Override + @NotNull + public GlobalSearchScope getDirtyScope() { + return myDirtyScope; + } + + private static Stream selectClassesInScope(Map classesPerFile, GlobalSearchScope searchScope) { + return classesPerFile.entrySet().stream().filter(e -> searchScope.contains(e.getKey())).flatMap(e -> Stream.of(e.getValue())); + } +} diff --git a/java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerHierarchySearchType.java b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerHierarchySearchType.java new file mode 100644 index 000000000000..7a19a6211c43 --- /dev/null +++ b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerHierarchySearchType.java @@ -0,0 +1,65 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.compiler.backwardRefs; + +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiNamedElement; +import com.intellij.psi.impl.source.PsiFileWithStubSupport; +import org.jetbrains.jps.backwardRefs.ByteArrayEnumerator; +import org.jetbrains.jps.backwardRefs.LightRef; + +import java.util.Collection; + +enum CompilerHierarchySearchType { + DIRECT_INHERITOR { + @Override + T[] performSearchInFile(Collection definitions, + PsiNamedElement baseElement, + ByteArrayEnumerator nameEnumerator, + PsiFileWithStubSupport file, + LanguageLightRefAdapter adapter) { + return (T[])adapter.findDirectInheritorCandidatesInFile(definitions, nameEnumerator, file, baseElement); + } + + @Override + Class getRequiredClass(LanguageLightRefAdapter adapter) { + return adapter.getHierarchyObjectClass(); + } + }, + FUNCTIONAL_EXPRESSION { + @Override + T[] performSearchInFile(Collection definitions, + PsiNamedElement baseElement, + ByteArrayEnumerator nameEnumerator, + PsiFileWithStubSupport file, + LanguageLightRefAdapter adapter) { + return (T[])adapter.findFunExpressionsInFile(definitions, file); + } + + @Override + Class getRequiredClass(LanguageLightRefAdapter adapter) { + return adapter.getFunExprClass(); + } + }; + + abstract T[] performSearchInFile(Collection definitions, + PsiNamedElement baseElement, + ByteArrayEnumerator nameEnumerator, + PsiFileWithStubSupport file, + LanguageLightRefAdapter adapter); + + abstract Class getRequiredClass(LanguageLightRefAdapter adapter); +} diff --git a/java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerReferenceReader.java b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerReferenceReader.java index 995ae637a853..2c21dde2bf78 100644 --- a/java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerReferenceReader.java +++ b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerReferenceReader.java @@ -15,30 +15,28 @@ */ package com.intellij.compiler.backwardRefs; -import com.intellij.compiler.ClassResolvingCompilerSearchAdapter; -import com.intellij.compiler.CompilerElement; -import com.intellij.compiler.CompilerSearchAdapter; import com.intellij.compiler.server.BuildManager; -import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Couple; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileWithId; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiManager; import com.intellij.psi.PsiNamedElement; +import com.intellij.psi.impl.source.PsiFileWithStubSupport; import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.util.ObjectUtils; -import com.intellij.util.SmartList; import com.intellij.util.containers.Queue; -import com.sun.tools.javac.util.Convert; import gnu.trove.THashMap; import gnu.trove.THashSet; import gnu.trove.TIntHashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.backwardRefs.ByteArrayEnumerator; import org.jetbrains.jps.backwardRefs.CompilerBackwardReferenceIndex; -import org.jetbrains.jps.backwardRefs.LightUsage; +import org.jetbrains.jps.backwardRefs.LightRef; import java.io.File; import java.io.IOException; @@ -47,8 +45,6 @@ import java.util.*; import static java.util.stream.Collectors.*; class CompilerReferenceReader { - private final static Logger LOG = Logger.getInstance(CompilerReferenceReader.class); - private final CompilerBackwardReferenceIndex myIndex; private CompilerReferenceReader(File buildDir) throws IOException { @@ -56,21 +52,16 @@ class CompilerReferenceReader { } @Nullable - TIntHashSet findReferentFileIds(@NotNull CompilerElement element, - @NotNull CompilerSearchAdapter adapter, - boolean checkBaseClassAmbiguity) { - LightUsage usage = asLightUsage(element); - + TIntHashSet findReferentFileIds(@NotNull LightRef ref, boolean checkBaseClassAmbiguity) { + LightRef.LightClassHierarchyElementDef hierarchyElement = ref instanceof LightRef.LightClassHierarchyElementDef ? + (LightRef.LightClassHierarchyElementDef)ref : + ((LightRef.LightMember)ref).getOwner(); TIntHashSet set = new TIntHashSet(); - if (adapter.needOverrideElement()) { - final LightUsage[] hierarchy = getWholeHierarchy(usage.getOwner(), checkBaseClassAmbiguity); - if (hierarchy == null) return null; - for (LightUsage aClass : hierarchy) { - final LightUsage overriderUsage = usage.override(aClass); - addUsages(overriderUsage, set); - } - } else { - addUsages(usage, set); + final LightRef.NamedLightRef[] hierarchy = getWholeHierarchy(hierarchyElement, checkBaseClassAmbiguity); + if (hierarchy == null) return null; + for (LightRef.NamedLightRef aClass : hierarchy) { + final LightRef overriderUsage = aClass.override(aClass.getName()); + addUsages(overriderUsage, set); } return set; } @@ -82,56 +73,63 @@ class CompilerReferenceReader { * 2nd map: candidates. One need to check that these classes are really direct inheritors */ @Nullable - Couple> getDirectInheritors(@NotNull PsiNamedElement baseClass, - @Nullable CompilerReferenceServiceImpl.CompilerElementInfo classSearchElementInfo, - @NotNull ClassResolvingCompilerSearchAdapter inheritorSearchAdapter, - @NotNull GlobalSearchScope searchScope, - @NotNull GlobalSearchScope dirtyScope, - @NotNull Project project, - @NotNull FileType fileType) { - if (classSearchElementInfo == null) return null; - LOG.assertTrue(classSearchElementInfo.searchElements.length == 1); - - Collection candidates = myIndex.getBackwardHierarchyMap().get(asLightUsage(classSearchElementInfo.searchElements[0])); + Couple> getDirectInheritors(@NotNull PsiNamedElement baseClass, + @NotNull LightRef searchElement, + @NotNull GlobalSearchScope searchScope, + @NotNull GlobalSearchScope dirtyScope, + @NotNull Project project, + @NotNull FileType fileType, + @NotNull CompilerHierarchySearchType searchType) { + Collection candidates = myIndex.getBackwardHierarchyMap().get(searchElement); if (candidates == null) return Couple.of(Collections.emptyMap(), Collections.emptyMap()); - Set> suitableClasses = new THashSet<>(); - for (LanguageLightUsageConverter converter : LanguageLightUsageConverter.INSTANCES) { - if (fileType == converter.getFileSourceType()) { - suitableClasses.addAll(converter.getLanguageLightUsageClasses()); - break; - } - } - - final GlobalSearchScope effectiveSearchScope = GlobalSearchScope.notScope(dirtyScope).intersectWith(searchScope); - - Map> candidatesPerFile = candidates + GlobalSearchScope effectiveSearchScope = GlobalSearchScope.notScope(dirtyScope).intersectWith(searchScope); + LanguageLightRefAdapter adapter = CompilerReferenceServiceImpl.findAdapterForFileType(fileType); + Class requiredLightRefClass = searchType.getRequiredClass(adapter); + Map> candidatesPerFile = candidates .stream() - .filter(def -> suitableClasses.contains(def.getUsage().getClass())) + .filter(def -> requiredLightRefClass.isInstance(def.getRef())) .map(definition -> { final VirtualFile file = findFile(definition.getFileId()); - return file != null && effectiveSearchScope.contains(file) ? new DecodedInheritorCandidate(getName(definition), file) : null; + if (file != null && effectiveSearchScope.contains(file)) { + return new Object() { + final VirtualFile containingFile = file; + final LightRef def = definition.getRef(); + }; + } + else { + return null; + } }) .filter(Objects::nonNull) - .collect(groupingBy(DecodedInheritorCandidate::getDeclarationFile, mapping(DecodedInheritorCandidate::getQName, toCollection(SmartList::new)))); + .collect(groupingBy(x -> x.containingFile, mapping(x -> x.def, toList()))); if (candidatesPerFile.isEmpty()) return Couple.of(Collections.emptyMap(), Collections.emptyMap()); Map inheritors = new THashMap<>(candidatesPerFile.size()); Map inheritorCandidates = new THashMap<>(); - candidatesPerFile.forEach((file, directInheritors) -> { - final T[] currInheritors = inheritorSearchAdapter.getCandidatesFromFile(directInheritors, baseClass, file, project); + final PsiManager psiManager = ReadAction.compute(() -> PsiManager.getInstance(project)); + + candidatesPerFile.forEach((file, directInheritors) -> ReadAction.run(() -> { + final PsiFileWithStubSupport psiFile = (PsiFileWithStubSupport)ReadAction.compute(() -> psiManager.findFile(file)); + final T[] currInheritors = searchType.performSearchInFile(directInheritors, baseClass, myIndex.getByteSeqEum(), psiFile, adapter); if (currInheritors.length == directInheritors.size()) { inheritors.put(file, currInheritors); - } else { + } + else { inheritorCandidates.put(file, currInheritors); } - }); + })); return Couple.of(inheritors, inheritorCandidates); } + @NotNull + ByteArrayEnumerator getNameEnumerator() { + return myIndex.getByteSeqEum(); + } + void close() { myIndex.close(); } @@ -149,7 +147,7 @@ class CompilerReferenceReader { } } - private void addUsages(LightUsage usage, TIntHashSet sink) { + private void addUsages(LightRef usage, TIntHashSet sink) { final Collection usageFiles = myIndex.getBackwardReferenceMap().get(usage); if (usageFiles != null) { for (int fileId : usageFiles) { @@ -161,19 +159,6 @@ class CompilerReferenceReader { } } - @NotNull - private LightUsage asLightUsage(@NotNull CompilerElement element) { - LightUsage usage = null; - for (LanguageLightUsageConverter converter : LanguageLightUsageConverter.INSTANCES) { - usage = converter.asLightUsage(element, myIndex.getByteSeqEum()); - if (usage != null) { - break; - } - } - LOG.assertTrue(usage != null); - return usage; - } - private VirtualFile findFile(int id) { try { String path = myIndex.getFilePathEnumerator().valueOf(id); @@ -186,14 +171,14 @@ class CompilerReferenceReader { } @Nullable("return null if the class hierarchy contains ambiguous qualified names") - private LightUsage[] getWholeHierarchy(LightUsage aClass, boolean checkBaseClassAmbiguity) { - Set result = new THashSet<>(); - Queue q = new Queue<>(10); - q.addLast(aClass); + private LightRef.NamedLightRef[] getWholeHierarchy(LightRef.LightClassHierarchyElementDef hierarchyElement, boolean checkBaseClassAmbiguity) { + Set result = new THashSet<>(); + Queue q = new Queue<>(10); + q.addLast(hierarchyElement); while (!q.isEmpty()) { - LightUsage curClass = q.pullFirst(); + LightRef.NamedLightRef curClass = q.pullFirst(); if (result.add(curClass)) { - if (checkBaseClassAmbiguity || curClass != aClass) { + if (checkBaseClassAmbiguity || curClass != hierarchyElement) { final Collection definitionFiles = myIndex.getBackwardClassDefinitionMap().get(curClass); if (definitionFiles.size() != 1) { return null; @@ -202,39 +187,14 @@ class CompilerReferenceReader { final Collection subClassDefs = myIndex.getBackwardHierarchyMap().get(curClass); if (subClassDefs != null) { for (CompilerBackwardReferenceIndex.LightDefinition subclass : subClassDefs) { - q.addLast(subclass.getUsage()); + final LightRef ref = subclass.getRef(); + if (ref instanceof LightRef.LightClassHierarchyElementDef) { + q.addLast((LightRef.LightClassHierarchyElementDef) ref); + } } } } } - return result.toArray(new LightUsage[result.size()]); - } - - @NotNull - private String getName(CompilerBackwardReferenceIndex.LightDefinition def) { - try { - return Convert.utf2string(ObjectUtils.notNull(myIndex.getByteSeqEum().valueOf(def.getUsage().getName()))); - } - catch (IOException e) { - throw new RuntimeException(e); - } - } - - private static class DecodedInheritorCandidate { - private final String qName; - private final VirtualFile declarationFile; - - private DecodedInheritorCandidate(String name, VirtualFile file) { - qName = name; - declarationFile = file; - } - - public VirtualFile getDeclarationFile() { - return declarationFile; - } - - public String getQName() { - return qName; - } + return result.toArray(new LightRef.NamedLightRef[result.size()]); } } \ No newline at end of file diff --git a/java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerReferenceServiceImpl.java b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerReferenceServiceImpl.java index 9900e1fd8125..7cf8a437061d 100644 --- a/java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerReferenceServiceImpl.java +++ b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerReferenceServiceImpl.java @@ -15,13 +15,12 @@ */ package com.intellij.compiler.backwardRefs; -import com.intellij.compiler.ClassResolvingCompilerSearchAdapter; -import com.intellij.compiler.CompilerElement; +import com.intellij.compiler.CompilerDirectHierarchyInfo; import com.intellij.compiler.CompilerReferenceService; -import com.intellij.compiler.CompilerSearchAdapter; import com.intellij.compiler.server.BuildManager; import com.intellij.compiler.server.BuildManagerListener; import com.intellij.lang.injection.InjectedLanguageManager; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.compiler.*; import com.intellij.openapi.fileTypes.FileType; @@ -35,8 +34,8 @@ import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.roots.impl.LibraryScopeCache; import com.intellij.openapi.util.Couple; import com.intellij.openapi.util.ModificationTracker; -import com.intellij.openapi.util.UserDataHolderBase; -import com.intellij.openapi.vfs.*; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileWithId; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiNamedElement; import com.intellij.psi.search.GlobalSearchScope; @@ -45,25 +44,23 @@ import com.intellij.psi.util.CachedValuesManager; import com.intellij.psi.util.PsiModificationTracker; import com.intellij.psi.util.PsiUtilCore; import com.intellij.util.containers.ConcurrentFactoryMap; -import com.intellij.util.containers.ContainerUtil; import com.intellij.util.indexing.FileBasedIndex; import gnu.trove.THashSet; import gnu.trove.TIntHashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; +import org.jetbrains.jps.backwardRefs.LightRef; -import java.util.Collections; -import java.util.Map; -import java.util.Set; -import java.util.UUID; +import java.util.*; import java.util.concurrent.atomic.LongAdder; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.stream.Collectors; import java.util.stream.Stream; -import static com.intellij.psi.search.GlobalSearchScope.*; +import static com.intellij.psi.search.GlobalSearchScope.getScopeRestrictedByFileTypes; +import static com.intellij.psi.search.GlobalSearchScope.notScope; public class CompilerReferenceServiceImpl extends CompilerReferenceService implements ModificationTracker { private final Set myFileTypes; @@ -79,11 +76,9 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple public CompilerReferenceServiceImpl(Project project) { super(project); - myDirtyModulesHolder = new DirtyModulesHolder(); myProjectFileIndex = ProjectRootManager.getInstance(project).getFileIndex(); - myFileTypes = Collections.unmodifiableSet(Stream.of(LanguageLightUsageConverter.INSTANCES) - .map(LanguageLightUsageConverter::getFileSourceType) - .collect(Collectors.toSet())); + myFileTypes = Stream.of(LanguageLightRefAdapter.INSTANCES).flatMap(a -> a.getFileTypes().stream()).collect(Collectors.toSet()); + myDirtyModulesHolder = new DirtyModulesHolder(this); } @Override @@ -110,7 +105,7 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple } private void compilationFinished(int errors, CompileContext context) { - BuildManager.getInstance().runCommand(() -> { + Runnable compilationFinished = () -> { final Module[] compilationModules = context.getCompileScope().getAffectedModules(); Set modulesWithErrors; if (errors != 0) { @@ -131,52 +126,12 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple myCompilationCount.increment(); openReaderIfNeed(); - }); + }; + executeOnBuildThread(compilationFinished); } }); - VirtualFileManager.getInstance().addVirtualFileListener(new VirtualFileAdapter() { - @Override - public void fileCreated(@NotNull VirtualFileEvent event) { - processChange(event.getFile()); - } - - @Override - public void fileCopied(@NotNull VirtualFileCopyEvent event) { - processChange(event.getFile()); - } - - @Override - public void fileMoved(@NotNull VirtualFileMoveEvent event) { - processChange(event.getFile()); - } - - @Override - public void beforePropertyChange(@NotNull VirtualFilePropertyEvent event) { - if (VirtualFile.PROP_NAME.equals(event.getPropertyName()) || VirtualFile.PROP_SYMLINK_TARGET.equals(event.getPropertyName())) { - processChange(event.getFile()); - } - } - - @Override - public void beforeContentsChange(@NotNull VirtualFileEvent event) { - processChange(event.getFile()); - } - - @Override - public void beforeFileDeletion(@NotNull VirtualFileEvent event) { - processChange(event.getFile()); - } - - @Override - public void beforeFileMovement(@NotNull VirtualFileMoveEvent event) { - processChange(event.getFile()); - } - - private void processChange(VirtualFile file) { - myDirtyModulesHolder.fileChanged(file); - } - }, myProject); + myDirtyModulesHolder.installVFSListener(); ProgressManager.getInstance().run(new Task.Backgroundable(myProject, CompilerBundle.message("compiler.ref.service.validation.task.name")) { @Override @@ -184,7 +139,7 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple indicator.setText(CompilerBundle.message("compiler.ref.service.validation.progress.text")); CompileScope projectCompileScope = compilerManager.createProjectCompileScope(myProject); boolean isUpToDate = compilerManager.isUpToDate(projectCompileScope); - BuildManager.getInstance().runCommand(() -> { + executeOnBuildThread(() -> { if (isUpToDate) { myDirtyModulesHolder.compilerActivityFinished(projectCompileScope.getAffectedModules(), Module.EMPTY_ARRAY); myCompilationCount.increment(); @@ -206,76 +161,91 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple @Nullable @Override - public GlobalSearchScope getScopeWithoutCodeReferences(@NotNull PsiElement element, @NotNull CompilerSearchAdapter adapter) { + public GlobalSearchScope getScopeWithoutCodeReferences(@NotNull PsiElement element) { if (!isServiceEnabledFor(element)) return null; return CachedValuesManager.getCachedValue(element, - () -> CachedValueProvider.Result.create(new ConcurrentFactoryMap() { - @Nullable - @Override - protected GlobalSearchScope create(CompilerSearchAdapter key) { - return calculateScopeWithoutReferences(element, key); - } - }, - PsiModificationTracker.MODIFICATION_COUNT, this)).get(adapter); + () -> CachedValueProvider.Result.create(calculateScopeWithoutReferences(element), + PsiModificationTracker.MODIFICATION_COUNT, + this)); } @Nullable @Override - public CompilerDirectInheritorInfo getDirectInheritors(@NotNull PsiNamedElement aClass, - @NotNull GlobalSearchScope useScope, - @NotNull GlobalSearchScope searchScope, - @NotNull ClassResolvingCompilerSearchAdapter inheritorSearchAdapter, - @NotNull FileType searchFileType) { - if (!isServiceEnabledFor(aClass) || searchScope == LibraryScopeCache.getInstance(myProject).getLibrariesOnlyScope()) return null; + public CompilerDirectHierarchyInfo getDirectInheritors(@NotNull PsiNamedElement aClass, + @NotNull GlobalSearchScope useScope, + @NotNull GlobalSearchScope searchScope, + @NotNull FileType searchFileType) { + return getHierarchyInfo(aClass, useScope, searchScope, searchFileType, CompilerHierarchySearchType.DIRECT_INHERITOR); + } + + @Nullable + @Override + public CompilerDirectHierarchyInfo getFunExpressions(@NotNull PsiNamedElement functionalInterface, + @NotNull GlobalSearchScope useScope, + @NotNull GlobalSearchScope searchScope, + @NotNull FileType searchFileType) { + return getHierarchyInfo(functionalInterface, useScope, searchScope, searchFileType, CompilerHierarchySearchType.FUNCTIONAL_EXPRESSION); + } + + @Nullable + private CompilerDirectHierarchyInfo getHierarchyInfo(@NotNull PsiNamedElement aClass, + @NotNull GlobalSearchScope useScope, + @NotNull GlobalSearchScope searchScope, + @NotNull FileType searchFileType, + @NotNull CompilerHierarchySearchType searchType) { + if (!isServiceEnabledFor(aClass) || searchScope == LibraryScopeCache.getInstance(myProject).getLibrariesOnlyScope()) return null; Couple> directInheritorsAndCandidates = - CachedValuesManager.getCachedValue(aClass, () -> CachedValueProvider.Result.create(calculateDirectInheritors(aClass, - inheritorSearchAdapter, - useScope, - searchFileType), - PsiModificationTracker.MODIFICATION_COUNT, - this)); + CachedValuesManager.getCachedValue(aClass, () -> CachedValueProvider.Result.create( + new ConcurrentFactoryMap>>() { + @Nullable + @Override + protected Couple> create(HierarchySearchKey key) { + return calculateDirectInheritors(aClass, + useScope, + key.mySearchFileType, + key.mySearchType); + } + }, PsiModificationTracker.MODIFICATION_COUNT, this)).get(new HierarchySearchKey(searchType, searchFileType)); if (directInheritorsAndCandidates == null) return null; GlobalSearchScope dirtyScope = myDirtyModulesHolder.getDirtyScope(); if (ElementPlace.LIB == ElementPlace.get(aClass.getContainingFile().getVirtualFile(), myProjectFileIndex)) { dirtyScope = dirtyScope.union(LibraryScopeCache.getInstance(myProject).getLibrariesOnlyScope()); } - return new CompilerDirectInheritorInfoImpl<>(directInheritorsAndCandidates, dirtyScope, searchScope); + return new CompilerHierarchyInfoImpl<>(directInheritorsAndCandidates, dirtyScope, searchScope); } private boolean isServiceEnabledFor(PsiElement element) { - return isServiceEnabled() && !InjectedLanguageManager.getInstance(myProject).isInjectedFragment(ReadAction.compute(() -> element.getContainingFile())); + return isServiceEnabled() && !InjectedLanguageManager.getInstance(myProject).isInjectedFragment(element.getContainingFile()); } private boolean isServiceEnabled() { return myReader != null && isEnabled(); } - private Couple> calculateDirectInheritors(@NotNull PsiNamedElement aClass, - @NotNull ClassResolvingCompilerSearchAdapter searchAdapter, - @NotNull GlobalSearchScope useScope, - @NotNull FileType searchFileType) { - final CompilerElementInfo searchElementInfo = asCompilerElements(aClass, searchAdapter, false); + private Couple> calculateDirectInheritors(@NotNull PsiNamedElement aClass, + @NotNull GlobalSearchScope useScope, + @NotNull FileType searchFileType, + @NotNull CompilerHierarchySearchType searchType) { + + final CompilerElementInfo searchElementInfo = asCompilerElements(aClass, false); + if (searchElementInfo == null) return null; + LightRef searchElement = searchElementInfo.searchElements[0]; + myReadDataLock.lock(); try { if (myReader == null) return null; - return myReader.getDirectInheritors(aClass, - searchElementInfo, - searchAdapter, - useScope, - myDirtyModulesHolder.getDirtyScope(), - myProject, - searchFileType); + return myReader.getDirectInheritors(aClass, searchElement, useScope, myDirtyModulesHolder.getDirtyScope(), myProject, searchFileType, searchType); } finally { myReadDataLock.unlock(); } } @Nullable - private GlobalSearchScope calculateScopeWithoutReferences(@NotNull PsiElement element, CompilerSearchAdapter adapter) { - TIntHashSet referentFileIds = getReferentFileIds(element, adapter); + private GlobalSearchScope calculateScopeWithoutReferences(@NotNull PsiElement element) { + TIntHashSet referentFileIds = getReferentFileIds(element); if (referentFileIds == null) return null; return getScopeRestrictedByFileTypes(new ScopeWithoutReferencesOnCompilation(referentFileIds).intersectWith(notScope(myDirtyModulesHolder.getDirtyScope())), @@ -283,45 +253,60 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple } @Nullable - private TIntHashSet getReferentFileIds(@NotNull PsiElement element, @NotNull CompilerSearchAdapter adapter) { - final CompilerElementInfo compilerElementInfo = asCompilerElements(element, adapter, true); + private TIntHashSet getReferentFileIds(@NotNull PsiElement element) { + final CompilerElementInfo compilerElementInfo = asCompilerElements(element, true); if (compilerElementInfo == null) return null; myReadDataLock.lock(); try { if (myReader == null) return null; TIntHashSet referentFileIds = new TIntHashSet(); - for (CompilerElement compilerElement : compilerElementInfo.searchElements) { - final TIntHashSet referents = myReader.findReferentFileIds(compilerElement, adapter, compilerElementInfo.place == ElementPlace.SRC); + for (LightRef ref : compilerElementInfo.searchElements) { + final TIntHashSet referents = myReader.findReferentFileIds(ref, compilerElementInfo.place == ElementPlace.SRC); if (referents == null) return null; referentFileIds.addAll(referents.toArray()); } return referentFileIds; + } finally { myReadDataLock.unlock(); } } @Nullable - private CompilerElementInfo asCompilerElements(@NotNull PsiElement psiElement, @NotNull CompilerSearchAdapter adapter, boolean buildHierarchyForLibraryElements) { - VirtualFile file = PsiUtilCore.getVirtualFile(psiElement); - ElementPlace place = ElementPlace.get(file, myProjectFileIndex); - if (place == null || (place == ElementPlace.SRC && myDirtyModulesHolder.contains(file))) { - return null; + private CompilerElementInfo asCompilerElements(@NotNull PsiElement psiElement, boolean buildHierarchyForLibraryElements) { + myReadDataLock.lock(); + try { + if (myReader == null) return null; + VirtualFile file = PsiUtilCore.getVirtualFile(psiElement); + ElementPlace place = ElementPlace.get(file, myProjectFileIndex); + if (place == null || (place == ElementPlace.SRC && myDirtyModulesHolder.contains(file))) { + return null; + } + final LanguageLightRefAdapter adapter = findAdapterForFileType(file.getFileType()); + final LightRef ref = ReadAction.compute(() -> adapter.asLightUsage(psiElement, myReader.getNameEnumerator())); + if (ref == null) return null; + if (place == ElementPlace.LIB && buildHierarchyForLibraryElements) { + final List elements = adapter.getHierarchyRestrictedToLibraryScope(ref, + psiElement, + myReader.getNameEnumerator(), + LibraryScopeCache.getInstance(myProject).getLibrariesOnlyScope()); + final LightRef[] fullHierarchy = new LightRef[elements.size() + 1]; + fullHierarchy[0] = ref; + int i = 1; + for (LightRef element : elements) { + fullHierarchy[i++] = element; + } + return new CompilerElementInfo(place, fullHierarchy); + } + else { + return new CompilerElementInfo(place, ref); + } + } finally { + myReadDataLock.unlock(); } - final CompilerElement compilerElement = ReadAction.compute(() -> adapter.asCompilerElement(psiElement)); - if (compilerElement == null) return null; - if (place == ElementPlace.LIB && buildHierarchyForLibraryElements) { - final CompilerElement[] elements = adapter.getHierarchyRestrictedToLibrariesScope(compilerElement, psiElement); - final CompilerElement[] fullHierarchy = new CompilerElement[elements.length + 1]; - fullHierarchy[0] = compilerElement; - System.arraycopy(elements, 0, fullHierarchy, 1, elements.length); - return new CompilerElementInfo(place, fullHierarchy); - } - else { - return new CompilerElementInfo(place, compilerElement); - } + } private void closeReaderIfNeed() { @@ -349,9 +334,9 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple @TestOnly @Nullable - public Set getReferentFiles(@NotNull PsiElement element, @NotNull CompilerSearchAdapter adapter) { + public Set getReferentFiles(@NotNull PsiElement element) { FileBasedIndex fileIndex = FileBasedIndex.getInstance(); - final TIntHashSet ids = getReferentFileIds(element, adapter); + final TIntHashSet ids = getReferentFileIds(element); if (ids == null) return null; Set fileSet = new THashSet<>(); ids.forEach(id -> { @@ -363,6 +348,35 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple return fileSet; } + ProjectFileIndex getFileIndex() { + return myProjectFileIndex; + } + + Set getFileTypes() { + return myFileTypes; + } + + Project getProject() { + return myProject; + } + + static LanguageLightRefAdapter findAdapterForFileType(@NotNull FileType fileType) { + for (LanguageLightRefAdapter adapter : LanguageLightRefAdapter.INSTANCES) { + if (adapter.getFileTypes().contains(fileType)) { + return adapter; + } + } + throw new AssertionError("adapter is not found for: " + fileType); + } + + private static void executeOnBuildThread(Runnable compilationFinished) { + if (ApplicationManager.getApplication().isUnitTestMode()) { + compilationFinished.run(); + } else { + BuildManager.getInstance().runCommand(compilationFinished); + } + } + private enum ElementPlace { SRC, LIB; @@ -405,103 +419,37 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple return myCompilationCount.longValue(); } - private class DirtyModulesHolder extends UserDataHolderBase { - private final Set myChangedModules = ContainerUtil.newHashSet(); - private final Set myChangedModulesDuringCompilation = ContainerUtil.newHashSet(); - private boolean myCompilationPhase; - - private final Object myLock = new Object(); - - private void compilerActivityStarted() { - synchronized (myLock) { - myCompilationPhase = true; - } - } - - private void compilerActivityFinished(Module[] affectedModules, Module[] markAsDirty) { - synchronized (myLock) { - myCompilationPhase = false; - - ContainerUtil.removeAll(myChangedModules, affectedModules); - Collections.addAll(myChangedModules, markAsDirty); - myChangedModules.addAll(myChangedModulesDuringCompilation); - myChangedModulesDuringCompilation.clear(); - } - } - - private GlobalSearchScope getDirtyScope() { - return CachedValuesManager.getManager(myProject).getCachedValue(this, () -> { - synchronized (myLock) { - final GlobalSearchScope dirtyScope = - myChangedModules.stream().map(Module::getModuleWithDependentsScope).reduce(EMPTY_SCOPE, (s1, s2) -> s1.union(s2)); - return CachedValueProvider.Result.create(dirtyScope, PsiModificationTracker.MODIFICATION_COUNT, CompilerReferenceServiceImpl.this); - } - }); - } - - private void fileChanged(VirtualFile file) { - if (myProjectFileIndex.isInSourceContent(file) && myFileTypes.contains(file.getFileType())) { - final Module module = myProjectFileIndex.getModuleForFile(file); - if (module != null) { - synchronized (myLock) { - if (myCompilationPhase) { - myChangedModulesDuringCompilation.add(module); - } else { - myChangedModules.add(module); - } - } - } - } - } - - private boolean contains(VirtualFile file) { - return getDirtyScope().contains(file); - } - } - static class CompilerElementInfo { final ElementPlace place; - final CompilerElement[] searchElements; + final LightRef[] searchElements; - private CompilerElementInfo(ElementPlace place, CompilerElement... searchElements) { - this.searchElements = searchElements; + private CompilerElementInfo(ElementPlace place, LightRef... searchElements) { this.place = place; + this.searchElements = searchElements; } } - private static class CompilerDirectInheritorInfoImpl implements CompilerDirectInheritorInfo { - private final GlobalSearchScope myDirtyScope; - private final GlobalSearchScope mySearchScope; - private Couple> myCandidatePerFile; + private static class HierarchySearchKey { + private final CompilerHierarchySearchType mySearchType; + private final FileType mySearchFileType; - private CompilerDirectInheritorInfoImpl(Couple> candidatePerFile, - GlobalSearchScope dirtyScope, - GlobalSearchScope searchScope) { - myCandidatePerFile = candidatePerFile; - myDirtyScope = dirtyScope; - mySearchScope = searchScope; + HierarchySearchKey(CompilerHierarchySearchType searchType, FileType searchFileType) { + mySearchType = searchType; + mySearchFileType = searchFileType; } @Override - @NotNull - public Stream getDirectInheritors() { - return selectClassesInScope(myCandidatePerFile.getFirst(), mySearchScope); + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + HierarchySearchKey key = (HierarchySearchKey)o; + return mySearchType == key.mySearchType && mySearchFileType == key.mySearchFileType; } @Override - @NotNull - public Stream getDirectInheritorCandidates() { - return selectClassesInScope(myCandidatePerFile.getSecond(), mySearchScope); - } - - @Override - @NotNull - public GlobalSearchScope getDirtyScope() { - return myDirtyScope; - } - - private static Stream selectClassesInScope(Map classesPerFile, GlobalSearchScope searchScope) { - return classesPerFile.entrySet().stream().filter(e -> searchScope.contains(e.getKey())).flatMap(e -> Stream.of(e.getValue())); + public int hashCode() { + return 31 * mySearchType.hashCode() + mySearchFileType.hashCode(); } } } diff --git a/java/compiler/impl/src/com/intellij/compiler/backwardRefs/DirtyModulesHolder.java b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/DirtyModulesHolder.java new file mode 100644 index 000000000000..4f335dba2c50 --- /dev/null +++ b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/DirtyModulesHolder.java @@ -0,0 +1,136 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.compiler.backwardRefs; + +import com.intellij.openapi.module.Module; +import com.intellij.openapi.util.UserDataHolderBase; +import com.intellij.openapi.vfs.*; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.CachedValuesManager; +import com.intellij.psi.util.PsiModificationTracker; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.Set; + +import static com.intellij.psi.search.GlobalSearchScope.EMPTY_SCOPE; + +class DirtyModulesHolder extends UserDataHolderBase { + private final CompilerReferenceServiceImpl myService; + private final Set myChangedModules = ContainerUtil.newHashSet(); + private final Set myChangedModulesDuringCompilation = ContainerUtil.newHashSet(); + private final Object myLock = new Object(); + + private boolean myCompilationPhase; + + public DirtyModulesHolder(@NotNull CompilerReferenceServiceImpl service){ + myService = service; + } + + void compilerActivityStarted() { + synchronized (myLock) { + myCompilationPhase = true; + } + } + + void compilerActivityFinished(Module[] affectedModules, Module[] markAsDirty) { + synchronized (myLock) { + myCompilationPhase = false; + + ContainerUtil.removeAll(myChangedModules, affectedModules); + Collections.addAll(myChangedModules, markAsDirty); + myChangedModules.addAll(myChangedModulesDuringCompilation); + myChangedModulesDuringCompilation.clear(); + } + } + + GlobalSearchScope getDirtyScope() { + return CachedValuesManager.getManager(myService.getProject()).getCachedValue(this, () -> { + synchronized (myLock) { + final GlobalSearchScope dirtyScope = + myChangedModules.stream().map(Module::getModuleWithDependentsScope).reduce(EMPTY_SCOPE, (s1, s2) -> s1.union(s2)); + return CachedValueProvider.Result.create(dirtyScope, PsiModificationTracker.MODIFICATION_COUNT, myService); + } + }); + } + + boolean contains(VirtualFile file) { + return getDirtyScope().contains(file); + } + + void installVFSListener() { + VirtualFileManager.getInstance().addVirtualFileListener(new VirtualFileAdapter() { + @Override + public void fileCreated(@NotNull VirtualFileEvent event) { + processChange(event.getFile()); + } + + @Override + public void fileCopied(@NotNull VirtualFileCopyEvent event) { + processChange(event.getFile()); + } + + @Override + public void fileMoved(@NotNull VirtualFileMoveEvent event) { + processChange(event.getFile()); + } + + @Override + public void beforePropertyChange(@NotNull VirtualFilePropertyEvent event) { + if (VirtualFile.PROP_NAME.equals(event.getPropertyName()) || VirtualFile.PROP_SYMLINK_TARGET.equals(event.getPropertyName())) { + processChange(event.getFile()); + } + } + + @Override + public void beforeContentsChange(@NotNull VirtualFileEvent event) { + processChange(event.getFile()); + } + + @Override + public void beforeFileDeletion(@NotNull VirtualFileEvent event) { + processChange(event.getFile()); + } + + @Override + public void beforeFileMovement(@NotNull VirtualFileMoveEvent event) { + processChange(event.getFile()); + } + + private void processChange(VirtualFile file) { + fileChanged(file); + } + + void fileChanged(VirtualFile file) { + if (myService.getFileIndex().isInSourceContent(file) && myService.getFileTypes().contains(file.getFileType())) { + final Module module = myService.getFileIndex().getModuleForFile(file); + if (module != null) { + synchronized (myLock) { + if (myCompilationPhase) { + myChangedModulesDuringCompilation.add(module); + } else { + myChangedModules.add(module); + } + } + } + } + } + }, myService.getProject()); + + } +} diff --git a/java/java-indexing-impl/src/com/intellij/compiler/JavaBaseCompilerSearchAdapter.java b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/JavaCompilerElementRetriever.java similarity index 52% rename from java/java-indexing-impl/src/com/intellij/compiler/JavaBaseCompilerSearchAdapter.java rename to java/compiler/impl/src/com/intellij/compiler/backwardRefs/JavaCompilerElementRetriever.java index 06178cd9da1f..a5216fe2f494 100644 --- a/java/java-indexing-impl/src/com/intellij/compiler/JavaBaseCompilerSearchAdapter.java +++ b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/JavaCompilerElementRetriever.java @@ -13,108 +13,61 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.compiler; +package com.intellij.compiler.backwardRefs; import com.intellij.lang.ASTNode; import com.intellij.openapi.application.ReadAction; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.impl.LibraryScopeCache; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; +import com.intellij.psi.impl.java.stubs.FunctionalExpressionStub; import com.intellij.psi.impl.java.stubs.PsiClassStub; -import com.intellij.psi.impl.java.stubs.impl.PsiClassStubImpl; import com.intellij.psi.impl.source.PsiFileImpl; import com.intellij.psi.impl.source.PsiFileWithStubSupport; -import com.intellij.psi.search.searches.ClassInheritorsSearch; +import com.intellij.psi.impl.source.tree.JavaElementType; +import com.intellij.psi.stubs.StubBase; import com.intellij.psi.stubs.StubElement; import com.intellij.psi.stubs.StubTree; -import com.intellij.psi.util.ClassUtil; -import com.intellij.util.ObjectUtils; -import com.intellij.util.Processor; +import com.intellij.psi.tree.TokenSet; +import gnu.trove.TIntHashSet; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collection; import java.util.List; -public class JavaBaseCompilerSearchAdapter implements ClassResolvingCompilerSearchAdapter { - public static final JavaBaseCompilerSearchAdapter INSTANCE = new JavaBaseCompilerSearchAdapter(); +public class JavaCompilerElementRetriever { + private final static TokenSet FUN_EXPR = TokenSet.create(JavaElementType.LAMBDA_EXPRESSION, JavaElementType.METHOD_REF_EXPRESSION); - @Override - public boolean needOverrideElement() { - return true; - } + @NotNull + static PsiFunctionalExpression[] retrieveFunExpressionsByIndices(@NotNull TIntHashSet indices, + @NotNull PsiFileWithStubSupport psiFile) { + StubTree tree = psiFile.getStubTree(); + boolean foreign = tree == null; + if (foreign) { + tree = ((PsiFileImpl)psiFile).calcStubTree(); + } - @Nullable - @Override - public CompilerElement asCompilerElement(@NotNull PsiElement element) { - if (mayBeVisibleOutsideOwnerFile(element)) { - if (element instanceof PsiField) { - final PsiField field = (PsiField)element; - final PsiClass aClass = field.getContainingClass(); - if (aClass == null || aClass instanceof PsiAnonymousClass) return null; - final String jvmOwnerName = ClassUtil.getJVMClassName(aClass); - final String name = field.getName(); - if (name == null || jvmOwnerName == null) return null; - return new CompilerElement.CompilerField(jvmOwnerName, name); - } - else if (element instanceof PsiMethod) { - final PsiClass aClass = ((PsiMethod)element).getContainingClass(); - if (aClass == null || aClass instanceof PsiAnonymousClass) return null; - final String jvmOwnerName = ClassUtil.getJVMClassName(aClass); - if (jvmOwnerName == null) return null; - final PsiMethod method = (PsiMethod)element; - final String name = method.isConstructor() ? "" : method.getName(); - final int parametersCount = method.getParameterList().getParametersCount(); - return new CompilerElement.CompilerMethod(jvmOwnerName, name, parametersCount); - } - else if (element instanceof PsiClass) { - final String jvmClassName = ClassUtil.getJVMClassName((PsiClass)element); - if (jvmClassName != null) { - return new CompilerElement.CompilerClass(jvmClassName); - } + PsiFunctionalExpression[] result = new PsiFunctionalExpression[indices.size()]; + int resIdx = 0; + int funExprIdx = 0; + for (StubElement element : tree.getPlainList()) { + if (FUN_EXPR.contains(element.getStubType()) && indices.contains(funExprIdx++)) { + result[resIdx++] = asPsi((FunctionalExpressionStub) element, psiFile, tree, foreign); } } - return null; + return result; } @NotNull - @Override - public CompilerElement[] getHierarchyRestrictedToLibrariesScope(@NotNull CompilerElement baseLibraryElement, @NotNull PsiElement baseLibraryPsi) { - final PsiClass baseClass = ObjectUtils.notNull(baseLibraryPsi instanceof PsiClass ? (PsiClass)baseLibraryPsi : ((PsiMember)baseLibraryPsi).getContainingClass()); - final List overridden = new ArrayList<>(); - Processor processor = c -> { - if (c.hasModifierProperty(PsiModifier.PRIVATE)) return true; - String qName = c.getQualifiedName(); - if (qName == null) return true; - overridden.add(baseLibraryElement.override(qName)); - return true; - }; - ClassInheritorsSearch.search(baseClass, LibraryScopeCache.getInstance(baseClass.getProject()).getLibrariesOnlyScope(), true).forEach(processor); - return overridden.toArray(new CompilerElement[overridden.size()]); + static PsiClass[] retrieveClassesByInternalNames(@NotNull String[] internalNames, + @NotNull PsiNamedElement baseClass, + @NotNull PsiFileWithStubSupport psiFile) { + Collection matchers = createClassMatcher(internalNames, baseClass); + return ReadAction.compute(() -> retrieveMatchedClasses(psiFile, matchers).toArray(PsiClass.EMPTY_ARRAY)); } - @NotNull - @Override - public PsiClass[] getCandidatesFromFile(@NotNull Collection classInternalNames, - @NotNull PsiNamedElement superClass, - @NotNull VirtualFile containingFile, - @NotNull Project project) { - Collection matchers = createClassMatcher(classInternalNames, superClass); - return ReadAction.compute(() -> retrieveMatchedClasses(containingFile, project, matchers).toArray(PsiClass.EMPTY_ARRAY)); - } - - private static boolean mayBeVisibleOutsideOwnerFile(@NotNull PsiElement element) { - if (!(element instanceof PsiModifierListOwner)) return true; - if (((PsiModifierListOwner)element).hasModifierProperty(PsiModifier.PRIVATE)) return false; - return true; - } - - private static List retrieveMatchedClasses(VirtualFile file, Project project, Collection matchers) { + private static List retrieveMatchedClasses(PsiFileWithStubSupport psiFile, Collection matchers) { final List result = new ArrayList<>(matchers.size()); - PsiFileWithStubSupport psiFile = ObjectUtils.notNull((PsiFileWithStubSupport)PsiManager.getInstance(project).findFile(file)); StubTree tree = psiFile.getStubTree(); boolean foreign = tree == null; if (foreign) { @@ -123,20 +76,21 @@ public class JavaBaseCompilerSearchAdapter implements ClassResolvingCompilerSear for (StubElement element : tree.getPlainList()) { if (element instanceof PsiClassStub && match((PsiClassStub)element, matchers)) { - result.add(asPsi((PsiClassStub)element, psiFile, tree, foreign)); + result.add(asPsi((StubBase)element, psiFile, tree, foreign)); } } return result; } - private static PsiClass asPsi(PsiClassStub stub, PsiFileWithStubSupport file, StubTree tree, boolean foreign) { + + private static T asPsi(StubBase stub, PsiFileWithStubSupport file, StubTree tree, boolean foreign) { if (foreign) { - final PsiClass cachedPsi = ((PsiClassStubImpl)stub).getCachedPsi(); + final T cachedPsi = (stub).getCachedPsi(); if (cachedPsi != null) return cachedPsi; final ASTNode ast = file.findTreeForStub(tree, stub); - return ast != null ? (PsiClass)ast.getPsi() : null; + return ast != null ? (T)ast.getPsi() : null; } return stub.getPsi(); } @@ -154,9 +108,9 @@ public class JavaBaseCompilerSearchAdapter implements ClassResolvingCompilerSear return false; } - private static Collection createClassMatcher(@NotNull Collection internalNames, @NotNull PsiNamedElement baseClass) { + private static Collection createClassMatcher(@NotNull String[] internalNames, @NotNull PsiNamedElement baseClass) { boolean matcherBySuperNameAdded = false; - final List matchers = new ArrayList<>(internalNames.size()); + final List matchers = new ArrayList<>(internalNames.length); for (String internalName : internalNames) { int curLast = internalName.length() - 1; while (true) { diff --git a/java/compiler/impl/src/com/intellij/compiler/backwardRefs/JavaLightUsageAdapter.java b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/JavaLightUsageAdapter.java new file mode 100644 index 000000000000..63ccf50b4238 --- /dev/null +++ b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/JavaLightUsageAdapter.java @@ -0,0 +1,143 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.compiler.backwardRefs; + +import com.intellij.ide.highlighter.JavaClassFileType; +import com.intellij.ide.highlighter.JavaFileType; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.roots.impl.LibraryScopeCache; +import com.intellij.psi.*; +import com.intellij.psi.impl.source.PsiFileWithStubSupport; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.search.searches.ClassInheritorsSearch; +import com.intellij.psi.util.ClassUtil; +import com.intellij.util.ObjectUtils; +import com.intellij.util.Processor; +import com.intellij.util.containers.ContainerUtil; +import com.sun.tools.javac.util.Convert; +import gnu.trove.TIntHashSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.backwardRefs.ByteArrayEnumerator; +import org.jetbrains.jps.backwardRefs.LightRef; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; + +public class JavaLightUsageAdapter implements LanguageLightRefAdapter { + @NotNull + @Override + public Set getFileTypes() { + return ContainerUtil.set(JavaFileType.INSTANCE, JavaClassFileType.INSTANCE); + } + + @Override + public LightRef asLightUsage(@NotNull PsiElement element, @NotNull ByteArrayEnumerator names) { + if (mayBeVisibleOutsideOwnerFile(element)) { + if (element instanceof PsiField) { + final PsiField field = (PsiField)element; + final PsiClass aClass = field.getContainingClass(); + if (aClass == null || aClass instanceof PsiAnonymousClass) return null; + final String jvmOwnerName = ClassUtil.getJVMClassName(aClass); + final String name = field.getName(); + if (name == null || jvmOwnerName == null) return null; + return new LightRef.JavaLightFieldRef(id(jvmOwnerName, names), id(name, names)); + } + else if (element instanceof PsiMethod) { + final PsiClass aClass = ((PsiMethod)element).getContainingClass(); + if (aClass == null || aClass instanceof PsiAnonymousClass) return null; + final String jvmOwnerName = ClassUtil.getJVMClassName(aClass); + if (jvmOwnerName == null) return null; + final PsiMethod method = (PsiMethod)element; + final String name = method.isConstructor() ? "" : method.getName(); + final int parametersCount = method.getParameterList().getParametersCount(); + return new LightRef.JavaLightMethodRef(id(jvmOwnerName, names), id(name, names), parametersCount); + } + else if (element instanceof PsiClass) { + final String jvmClassName = ClassUtil.getJVMClassName((PsiClass)element); + if (jvmClassName != null) { + return new LightRef.JavaLightClassRef(id(jvmClassName, names)); + } + } + } + return null; + } + + @NotNull + @Override + public List getHierarchyRestrictedToLibraryScope(@NotNull LightRef baseRef, + @NotNull PsiElement basePsi, + @NotNull ByteArrayEnumerator names, @NotNull GlobalSearchScope libraryScope) { + final PsiClass baseClass = ObjectUtils.notNull(basePsi instanceof PsiClass ? (PsiClass)basePsi : ((PsiMember)basePsi).getContainingClass()); + + final List overridden = new ArrayList<>(); + Processor processor = c -> { + if (c.hasModifierProperty(PsiModifier.PRIVATE)) return true; + String qName = c.getQualifiedName(); + if (qName == null) return true; + overridden.add(baseRef.override(id(qName, names))); + return true; + }; + + ClassInheritorsSearch.search(baseClass, LibraryScopeCache.getInstance(baseClass.getProject()).getLibrariesOnlyScope(), true).forEach(processor); + return overridden; + + } + + @NotNull + @Override + public Class getHierarchyObjectClass() { + return LightRef.JavaLightClassRef.class; + } + + @NotNull + @Override + public Class getFunExprClass() { + return LightRef.JavaLightFunExprDef.class; + } + + @NotNull + @Override + public PsiClass[] findDirectInheritorCandidatesInFile(@NotNull Collection classes, + @NotNull ByteArrayEnumerator byteArrayEnumerator, + @NotNull PsiFileWithStubSupport file, + @NotNull PsiNamedElement superClass) { + String[] internalNames = classes.stream().map(LightRef.NamedLightRef::getName).map(byteArrayEnumerator::getName).toArray(String[]::new); + return JavaCompilerElementRetriever.retrieveClassesByInternalNames(internalNames, superClass, file); + } + + @NotNull + @Override + public PsiFunctionalExpression[] findFunExpressionsInFile(@NotNull Collection funExpressions, + @NotNull PsiFileWithStubSupport file) { + TIntHashSet requiredIndices = new TIntHashSet(funExpressions.size()); + for (LightRef.LightFunExprDef funExpr : funExpressions) { + requiredIndices.add(funExpr.getId()); + } + return JavaCompilerElementRetriever.retrieveFunExpressionsByIndices(requiredIndices, file); + } + + private static boolean mayBeVisibleOutsideOwnerFile(@NotNull PsiElement element) { + if (!(element instanceof PsiModifierListOwner)) return true; + if (((PsiModifierListOwner)element).hasModifierProperty(PsiModifier.PRIVATE)) return false; + return true; + } + + private static int id(String name, ByteArrayEnumerator names) { + return names.enumerate(Convert.string2utf(name)); + } +} diff --git a/java/compiler/impl/src/com/intellij/compiler/backwardRefs/LanguageLightRefAdapter.java b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/LanguageLightRefAdapter.java new file mode 100644 index 000000000000..e7705efb53b3 --- /dev/null +++ b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/LanguageLightRefAdapter.java @@ -0,0 +1,92 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.compiler.backwardRefs; + +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiNamedElement; +import com.intellij.psi.impl.source.PsiFileWithStubSupport; +import com.intellij.psi.search.GlobalSearchScope; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.backwardRefs.ByteArrayEnumerator; +import org.jetbrains.jps.backwardRefs.LightRef; + +import java.util.Collection; +import java.util.List; +import java.util.Set; + +/** + * An interface to provide connection between compact internal representation of indexed elements and PSI + */ +public interface LanguageLightRefAdapter { + LanguageLightRefAdapter[] INSTANCES = new LanguageLightRefAdapter[]{new JavaLightUsageAdapter()}; + + @NotNull + Set getFileTypes(); + + /** + * @param element PSI element written in corresponding language + * @param names enumerator to encode string names + * @return + */ + @Nullable + LightRef asLightUsage(@NotNull PsiElement element, @NotNull ByteArrayEnumerator names); + + /** + * @return "hierarchy" of given element inside the libraries scope. + */ + @NotNull + List getHierarchyRestrictedToLibraryScope(@NotNull LightRef baseRef, + @NotNull PsiElement basePsi, + @NotNull ByteArrayEnumerator names, + @NotNull GlobalSearchScope libraryScope); + + /** + * class in java, class or object in some other jvm languages. used in direct inheritor search. This class object will be used to filter + * inheritors of corresponding language among of other inheritors. + * + * name of this LightUsage is always enumerated internal string name of language object, eg.: A$1$B + */ + @NotNull + Class getHierarchyObjectClass(); + + /** + * functional expression: lambda or method reference. used in functional expression search + * + * name of this LightUsage is always order-index inside source-code file + */ + @NotNull + Class getFunExprClass(); + + /** + * @return classes that can be inheritors of given superClass. This method shouldn't directly check are + * found elements really inheritors. + */ + @NotNull + Clazz[] findDirectInheritorCandidatesInFile(@NotNull Collection internalNames, + @NotNull ByteArrayEnumerator byteArrayEnumerator, + @NotNull PsiFileWithStubSupport file, + @NotNull PsiNamedElement superClass); + + /** + * @param indices - ordinal-numbers (corresponding to compiler tree index visitor) of required functional expressions. + * @return functional expressions for given functional type. Should return + */ + @NotNull + FunExpr[] findFunExpressionsInFile(@NotNull Collection indices, + @NotNull PsiFileWithStubSupport file); +} diff --git a/java/compiler/impl/src/com/intellij/compiler/backwardRefs/LanguageLightUsageConverter.java b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/LanguageLightUsageConverter.java deleted file mode 100644 index 43771481478c..000000000000 --- a/java/compiler/impl/src/com/intellij/compiler/backwardRefs/LanguageLightUsageConverter.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2000-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.compiler.backwardRefs; - -import com.intellij.compiler.CompilerElement; -import com.intellij.openapi.fileTypes.FileType; -import com.intellij.openapi.fileTypes.StdFileTypes; -import com.intellij.util.containers.ContainerUtil; -import com.sun.tools.javac.util.Convert; -import org.jetbrains.jps.backwardRefs.ByteArrayEnumerator; -import org.jetbrains.jps.backwardRefs.LightUsage; - -import java.util.Set; - -public interface LanguageLightUsageConverter { - LanguageLightUsageConverter[] INSTANCES = new LanguageLightUsageConverter[]{new Java()}; - - LightUsage asLightUsage(CompilerElement element, ByteArrayEnumerator names); - - FileType getFileSourceType(); - - Set> getLanguageLightUsageClasses(); - - class Java implements LanguageLightUsageConverter { - private static final Set> JAVA_LIGHT_USAGE_CLASSES = - ContainerUtil.set(LightUsage.LightClassUsage.class, LightUsage.LightMethodUsage.class, LightUsage.LightFieldUsage.class); - - @Override - public LightUsage asLightUsage(CompilerElement element, ByteArrayEnumerator names) { - if (element instanceof CompilerElement.CompilerClass) { - return new LightUsage.LightClassUsage(id(((CompilerElement.CompilerClass)element).getJavacName(), names)); - - } - else if (element instanceof CompilerElement.CompilerMethod) { - final CompilerElement.CompilerMethod method = (CompilerElement.CompilerMethod)element; - return new LightUsage.LightMethodUsage(id(method.getJavacClassName(), names), - id(method.getJavacMethodName(), names), - method.getJavacParameterCount()); - - } - else if (element instanceof CompilerElement.CompilerField) { - final CompilerElement.CompilerField field = (CompilerElement.CompilerField)element; - return new LightUsage.LightFieldUsage(id(field.getJavacClassName(), names), - id(field.getJavacName(), names)); - - } - else if (element instanceof CompilerElement.CompilerFunExpr) { - final CompilerElement.CompilerFunExpr field = (CompilerElement.CompilerFunExpr)element; - return new LightUsage.LightFunExprUsage(id(field.getJavacClassName(), names)); - - } - return null; - } - - @Override - public FileType getFileSourceType() { - return StdFileTypes.JAVA; - } - - @Override - public Set> getLanguageLightUsageClasses() { - return JAVA_LIGHT_USAGE_CLASSES; - } - - private static int id(String name, ByteArrayEnumerator names) { - return names.enumerate(Convert.string2utf(name)); - } - } -} diff --git a/java/java-indexing-impl/src/com/intellij/compiler/ClassResolvingCompilerSearchAdapter.java b/java/java-indexing-impl/src/com/intellij/compiler/ClassResolvingCompilerSearchAdapter.java deleted file mode 100644 index 3ddd559cc799..000000000000 --- a/java/java-indexing-impl/src/com/intellij/compiler/ClassResolvingCompilerSearchAdapter.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2000-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.compiler; - -import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiNamedElement; -import org.jetbrains.annotations.NotNull; - -import java.util.Collection; - -public interface ClassResolvingCompilerSearchAdapter extends CompilerSearchAdapter { - - /** - * @param classInternalNames - collection compiler internal name of classes (e.g. org.some.Main$1 for java anonymous class) - */ - @NotNull - T[] getCandidatesFromFile(@NotNull Collection classInternalNames, - @NotNull PsiNamedElement superClass, - @NotNull VirtualFile containingFile, - @NotNull Project project); -} diff --git a/java/java-indexing-impl/src/com/intellij/compiler/CompilerSearchAdapter.java b/java/java-indexing-impl/src/com/intellij/compiler/CompilerDirectHierarchyInfo.java similarity index 50% rename from java/java-indexing-impl/src/com/intellij/compiler/CompilerSearchAdapter.java rename to java/java-indexing-impl/src/com/intellij/compiler/CompilerDirectHierarchyInfo.java index 12919b0d476e..5f4ba5ea132c 100644 --- a/java/java-indexing-impl/src/com/intellij/compiler/CompilerSearchAdapter.java +++ b/java/java-indexing-impl/src/com/intellij/compiler/CompilerDirectHierarchyInfo.java @@ -16,16 +16,30 @@ package com.intellij.compiler; import com.intellij.psi.PsiElement; +import com.intellij.psi.search.GlobalSearchScope; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -public interface CompilerSearchAdapter { - - boolean needOverrideElement(); - - @Nullable - CompilerElement asCompilerElement(@NotNull PsiElement psi); +import java.util.stream.Stream; +/** + * represents search result for functional expressions or inheritance hierarchy of given interface/class + */ +public interface CompilerDirectHierarchyInfo { + /** + * Can be used as direct hierarchy children without explicit inheritance verification + */ @NotNull - CompilerElement[] getHierarchyRestrictedToLibrariesScope(@NotNull CompilerElement baseLibraryElement, @NotNull PsiElement baseLibraryPsi); + Stream getHierarchyChildren(); + + /** + * Must be explicitly checked do they are really direct children in hierarchy of classes or functional expressions + */ + @NotNull + Stream getHierarchyChildCandidates(); + + /** + * A scope where compiler based index search was not performed + */ + @NotNull + GlobalSearchScope getDirtyScope(); } diff --git a/java/java-indexing-impl/src/com/intellij/compiler/CompilerElement.java b/java/java-indexing-impl/src/com/intellij/compiler/CompilerElement.java deleted file mode 100644 index b9a70c61e8ed..000000000000 --- a/java/java-indexing-impl/src/com/intellij/compiler/CompilerElement.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2000-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.compiler; - -public abstract class CompilerElement { - public static final CompilerElement[] EMPTY_ARRAY = new CompilerElement[0]; - - public abstract CompilerElement override(String overriderName); - - public static class CompilerMethod extends CompilerElement { - private final String myJavacClassName; - private final String myJavacMethodName; - private final int myJavacParameterCount; - - CompilerMethod(String javacClassName, String javacMethodName, int javacParameterCount) { - myJavacClassName = javacClassName; - myJavacMethodName = javacMethodName; - myJavacParameterCount = javacParameterCount; - } - - public String getJavacClassName() { - return myJavacClassName; - } - - public String getJavacMethodName() { - return myJavacMethodName; - } - - public int getJavacParameterCount() { - return myJavacParameterCount; - } - - @Override - public CompilerElement override(String overriderName) { - return new CompilerMethod(overriderName, myJavacMethodName, myJavacParameterCount); - } - } - - public static class CompilerClass extends CompilerElement { - private final String myJavacName; - - CompilerClass(String javacName) { - myJavacName = javacName; - } - - public String getJavacName() { - return myJavacName; - } - - @Override - public CompilerElement override(String overriderName) { - return new CompilerClass(myJavacName); - } - } - - public static class CompilerField extends CompilerElement { - private final String myJavacClassName; - private final String myJavacName; - - CompilerField(String javacClassName, String javacName) { - myJavacClassName = javacClassName; - myJavacName = javacName; - } - - public String getJavacClassName() { - return myJavacClassName; - } - - public String getJavacName() { - return myJavacName; - } - - @Override - public CompilerElement override(String overriderName) { - return new CompilerField(overriderName, myJavacName); - } - } - - public static class CompilerFunExpr extends CompilerElement { - private final String myJavacClassName; - - CompilerFunExpr(String javacClassName) { - myJavacClassName = javacClassName; - } - - public String getJavacClassName() { - return myJavacClassName; - } - - @Override - public CompilerElement override(String overriderName) { - throw new UnsupportedOperationException(); - } - } -} diff --git a/java/java-indexing-impl/src/com/intellij/compiler/CompilerReferenceService.java b/java/java-indexing-impl/src/com/intellij/compiler/CompilerReferenceService.java index 233ee14fb383..c42884c332a5 100644 --- a/java/java-indexing-impl/src/com/intellij/compiler/CompilerReferenceService.java +++ b/java/java-indexing-impl/src/com/intellij/compiler/CompilerReferenceService.java @@ -26,8 +26,6 @@ import com.intellij.psi.search.GlobalSearchScope; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.stream.Stream; - public abstract class CompilerReferenceService extends AbstractProjectComponent { public static final RegistryValue IS_ENABLED_KEY = Registry.get("bytecode.ref.index"); @@ -40,37 +38,21 @@ public abstract class CompilerReferenceService extends AbstractProjectComponent } @Nullable - public abstract GlobalSearchScope getScopeWithoutCodeReferences(@NotNull PsiElement element, @NotNull CompilerSearchAdapter adapter); + public abstract GlobalSearchScope getScopeWithoutCodeReferences(@NotNull PsiElement element); @Nullable - public abstract CompilerDirectInheritorInfo getDirectInheritors(@NotNull PsiNamedElement aClass, - @NotNull GlobalSearchScope useScope, - @NotNull GlobalSearchScope searchScope, - @NotNull ClassResolvingCompilerSearchAdapter inheritorSearchAdapter, - @NotNull FileType searchFileType); + public abstract CompilerDirectHierarchyInfo getDirectInheritors(@NotNull PsiNamedElement aClass, + @NotNull GlobalSearchScope useScope, + @NotNull GlobalSearchScope searchScope, + @NotNull FileType searchFileType); + @Nullable + public abstract CompilerDirectHierarchyInfo getFunExpressions(@NotNull PsiNamedElement functionalInterface, + @NotNull GlobalSearchScope useScope, + @NotNull GlobalSearchScope searchScope, + @NotNull FileType searchFileType); public static boolean isEnabled() { return IS_ENABLED_KEY.asBoolean(); } - - public interface CompilerDirectInheritorInfo { - /** - * Can be used as direct inheritors without explicit inheritance verification - */ - @NotNull - Stream getDirectInheritors(); - - /** - * Must be explicitly checked do they are really direct inheritors - */ - @NotNull - Stream getDirectInheritorCandidates(); - - /** - * A scope where compiler based index search was not performed - */ - @NotNull - GlobalSearchScope getDirtyScope(); - } } diff --git a/java/java-indexing-impl/src/com/intellij/compiler/JavaCompilerReferencesCodeUsageScopeOptimizer.java b/java/java-indexing-impl/src/com/intellij/compiler/JavaCompilerReferencesCodeUsageScopeOptimizer.java index bae091e37c19..06dd10d82cc7 100644 --- a/java/java-indexing-impl/src/com/intellij/compiler/JavaCompilerReferencesCodeUsageScopeOptimizer.java +++ b/java/java-indexing-impl/src/com/intellij/compiler/JavaCompilerReferencesCodeUsageScopeOptimizer.java @@ -25,6 +25,6 @@ public class JavaCompilerReferencesCodeUsageScopeOptimizer implements ScopeOptim @Nullable @Override public GlobalSearchScope getScopeToExclude(@NotNull PsiElement element) { - return CompilerReferenceService.getInstance(element.getProject()).getScopeWithoutCodeReferences(element, JavaBaseCompilerSearchAdapter.INSTANCE); + return CompilerReferenceService.getInstance(element.getProject()).getScopeWithoutCodeReferences(element); } } diff --git a/java/java-indexing-impl/src/com/intellij/compiler/JavaFunctionalExpressionCompilerSearchAdapter.java b/java/java-indexing-impl/src/com/intellij/compiler/JavaFunctionalExpressionCompilerSearchAdapter.java deleted file mode 100644 index 2b333626b22f..000000000000 --- a/java/java-indexing-impl/src/com/intellij/compiler/JavaFunctionalExpressionCompilerSearchAdapter.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2000-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.compiler; - -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiElement; -import com.intellij.psi.util.ClassUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class JavaFunctionalExpressionCompilerSearchAdapter implements CompilerSearchAdapter { - public static final JavaFunctionalExpressionCompilerSearchAdapter INSTANCE = - new JavaFunctionalExpressionCompilerSearchAdapter(); - - @Override - public boolean needOverrideElement() { - return false; - } - - @Nullable - @Override - public CompilerElement asCompilerElement(@NotNull PsiElement psi) { - final String qualifiedName = ClassUtil.getJVMClassName((PsiClass)psi); - return qualifiedName == null ? null : new CompilerElement.CompilerFunExpr(qualifiedName); - } - - @NotNull - @Override - public CompilerElement[] getHierarchyRestrictedToLibrariesScope(@NotNull CompilerElement baseLibraryElement, @NotNull PsiElement baseLibraryPsi) { - return CompilerElement.EMPTY_ARRAY; - } -} diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaDirectInheritorsSearcher.java b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaDirectInheritorsSearcher.java index 8e4ad355ada7..e267486b576d 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaDirectInheritorsSearcher.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaDirectInheritorsSearcher.java @@ -15,8 +15,8 @@ */ package com.intellij.psi.impl.search; +import com.intellij.compiler.CompilerDirectHierarchyInfo; import com.intellij.compiler.CompilerReferenceService; -import com.intellij.compiler.JavaBaseCompilerSearchAdapter; import com.intellij.concurrency.JobLauncher; import com.intellij.ide.highlighter.JavaFileType; import com.intellij.openapi.application.ApplicationManager; @@ -76,10 +76,10 @@ public class JavaDirectInheritorsSearcher implements QueryExecutor info = performSearchUsingCompilerIndices(parameters, scope, project); + CompilerDirectHierarchyInfo info = performSearchUsingCompilerIndices(parameters, scope, project); if (info != null) { - if (!processInheritorCandidates(info.getDirectInheritors(), consumer, parameters.includeAnonymous(), false, baseClass)) return false; - if (!processInheritorCandidates(info.getDirectInheritorCandidates(), consumer, parameters.includeAnonymous(), true, baseClass)) return false; + if (!processInheritorCandidates(info.getHierarchyChildren(), consumer, parameters.includeAnonymous(), false, baseClass)) return false; + if (!processInheritorCandidates(info.getHierarchyChildCandidates(), consumer, parameters.includeAnonymous(), true, baseClass)) return false; scope = scope.intersectWith(info.getDirtyScope()); useScope = useScope.intersectWith(info.getDirtyScope()); } @@ -274,9 +274,9 @@ public class JavaDirectInheritorsSearcher implements QueryExecutor)() -> PsiUtil.getJarFile(aClass)); } - private static CompilerReferenceService.CompilerDirectInheritorInfo performSearchUsingCompilerIndices(@NotNull DirectClassInheritorsSearch.SearchParameters parameters, - @NotNull SearchScope useScope, - @NotNull Project project) { + private static CompilerDirectHierarchyInfo performSearchUsingCompilerIndices(@NotNull DirectClassInheritorsSearch.SearchParameters parameters, + @NotNull SearchScope useScope, + @NotNull Project project) { if (!(useScope instanceof GlobalSearchScope)) return null; SearchScope scope = parameters.getScope(); if (!(scope instanceof GlobalSearchScope)) return null; @@ -286,7 +286,6 @@ public class JavaDirectInheritorsSearcher implements QueryExecutor consumer) { List descriptors = calcDescriptors(p); + Project project = PsiUtilCore.getProjectInReadAction(p.getElementToSearch()); + if (project == null) return; + + SearchScope searchScope = ReadAction.compute(() -> p.getEffectiveSearchScope()); + if (searchScope instanceof GlobalSearchScope && !performSearchUsingCompilerIndices(descriptors, + (GlobalSearchScope)searchScope, + project, + consumer)) { + return; + } + AtomicInteger exprCount = new AtomicInteger(); AtomicInteger fileCount = new AtomicInteger(); @@ -112,13 +126,6 @@ public class JavaFunctionalExpressionSearcher extends QueryExecutorBase likelyNames = ContainerUtil.newLinkedHashSet(className); StubIndex.getInstance().processElements(JavaMethodParameterTypesIndex.getInstance().getKey(), className, - project, useScope, PsiMethod.class, method -> { + project, effectiveUseScope, PsiMethod.class, method -> { ProgressManager.checkCanceled(); likelyNames.add(method.getName()); return true; @@ -319,12 +326,50 @@ public class JavaFunctionalExpressionSearcher extends QueryExecutorBase processor = Processors.cancelableCollectProcessor(files); for (String word : likelyNames) { - helper.processFilesWithText(useScope, UsageSearchContext.IN_CODE, true, word, processor); + helper.processFilesWithText(effectiveUseScope, UsageSearchContext.IN_CODE, true, word, processor); } }); return files; } + } + private static boolean performSearchUsingCompilerIndices(@NotNull List descriptors, + @NotNull GlobalSearchScope searchScope, + @NotNull Project project, + @NotNull Processor consumer) { + CompilerReferenceService compilerReferenceService = CompilerReferenceService.getInstance(project); + for (SamDescriptor descriptor : descriptors) { + if (!processFunctionalExpressions(performSearchUsingCompilerIndices(descriptor, + searchScope, + compilerReferenceService), descriptor, consumer)) { + return false; + } + } + return true; + } + + private static CompilerDirectHierarchyInfo performSearchUsingCompilerIndices(@NotNull SamDescriptor descriptor, + @NotNull GlobalSearchScope searchScope, + @NotNull CompilerReferenceService service) { + return service.getFunExpressions(descriptor.samClass, descriptor.effectiveUseScope, searchScope, JavaFileType.INSTANCE); + } + + + private static boolean processFunctionalExpressions(@Nullable CompilerDirectHierarchyInfo funExprInfo, + @NotNull SamDescriptor descriptor, + @NotNull Processor consumer) { + if (funExprInfo != null) { + Iterator it = funExprInfo.getHierarchyChildren().iterator(); + while (it.hasNext()) { + PsiFunctionalExpression next = it.next(); + if (!consumer.process(next)) { + return false; + } + } + GlobalSearchScope dirtyScope = funExprInfo.getDirtyScope(); + descriptor.effectiveUseScope = descriptor.effectiveUseScope.intersectWith(dirtyScope); + } + return true; } } \ No newline at end of file diff --git a/java/java-tests/testData/compiler/bytecodeReferences/testInnerFunExpressions/Foo.java b/java/java-tests/testData/compiler/bytecodeReferences/testInnerFunExpressions/Foo.java new file mode 100644 index 000000000000..df8ad2472a4e --- /dev/null +++ b/java/java-tests/testData/compiler/bytecodeReferences/testInnerFunExpressions/Foo.java @@ -0,0 +1,42 @@ +import java.util.function.IntSupplier; +import java.util.Collections; + +class Foo { + + void m() { + + Runnable r = Collections::emptyList; + + Runnable r2 = () -> { + + + IntSupplier s = () -> 1; + + Runnable r3 = () -> { + + }; + + }; + + IntSupplier s2 = () -> 1; + } + + void m2() { + + Runnable r = () -> { + + Runnable r3 = () -> { + + IntSupplier s2 = () -> 1; + + Runnable r4 = () -> { + + }; + + }; + + IntSupplier s = () -> 1; + + }; + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/compiler/CompilerReferencesTest.java b/java/java-tests/testSrc/com/intellij/compiler/CompilerReferencesTest.java index e7d5c8a95c1e..d72162694c9c 100644 --- a/java/java-tests/testSrc/com/intellij/compiler/CompilerReferencesTest.java +++ b/java/java-tests/testSrc/com/intellij/compiler/CompilerReferencesTest.java @@ -24,11 +24,14 @@ import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtil; import com.intellij.testFramework.SkipSlowTestLocally; import com.intellij.testFramework.builders.JavaModuleFixtureBuilder; import com.intellij.util.containers.ContainerUtil; import java.util.Collection; +import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; @@ -55,37 +58,56 @@ public class CompilerReferencesTest extends AbstractCompilerAwareTest { public void testIsNotReady() { myFixture.configureByFile(getName() + "/Foo.java"); - assertNull(getReferentFilesForElementUnderCaret(JavaBaseCompilerSearchAdapter.INSTANCE)); + assertNull(getReferentFilesForElementUnderCaret()); } public void testSimpleUsagesInFullyCompiledProject() { myFixture.configureByFiles(getName() + "/Foo.java", getName() + "/Bar.java", getName() + "/Baz.java", getName() + "/FooImpl.java"); rebuildProject(); - final Set referents = getReferentFilesForElementUnderCaret(JavaBaseCompilerSearchAdapter.INSTANCE); + final Set referents = getReferentFilesForElementUnderCaret(); assertNotNull(referents); final Set filesWithReferences = referents.stream().map(VirtualFile::getName).collect(Collectors.toSet()); assertEquals(filesWithReferences, ContainerUtil.set("Baz.java", "Foo.java", "FooImpl.java")); myFixture.addFileToProject("SomeModification.java", ""); - assertNull(getReferentFilesForElementUnderCaret(JavaBaseCompilerSearchAdapter.INSTANCE)); + assertNull(getReferentFilesForElementUnderCaret()); } public void testLambda() { myFixture.configureByFiles(getName() + "/Foo.java", getName() + "/FooImpl.java", getName() + "/Bar.java", getName() + "/BarRef.java"); rebuildProject(); - final Set referents = getReferentFilesForElementUnderCaret(JavaFunctionalExpressionCompilerSearchAdapter.INSTANCE); - assertNotNull(referents); - final Set filesWithReferences = referents.stream().map(VirtualFile::getName).collect(Collectors.toSet()); - assertEquals(filesWithReferences, ContainerUtil.set("Bar.java", "BarRef.java")); + final CompilerDirectHierarchyInfo funExpressions = getFunctionalExpressionsForElementUnderCaret(); + List funExprs = funExpressions.getHierarchyChildren().collect(Collectors.toList()); + assertSize(2, funExprs); + } + + public void testInnerFunExpressions() { + myFixture.configureByFiles(getName() + "/Foo.java"); + rebuildProject(); + List funExpressions = + getFunExpressionsFor(myFixture.getJavaFacade().findClass(CommonClassNames.JAVA_LANG_RUNNABLE)).getHierarchyChildren().collect(Collectors.toList()); + assertSize(6, funExpressions); + + Set funTypeNames = funExpressions + .stream() + .map(PsiElement::getParent) + .map(PsiVariable.class::cast) + .map(PsiVariable::getType) + .map(PsiUtil::resolveClassInType) + .filter(Objects::nonNull) + .map(PsiClass::getQualifiedName) + .collect(Collectors.toSet()); + String funTypeName = assertOneElement(funTypeNames); + assertEquals(CommonClassNames.JAVA_LANG_RUNNABLE, funTypeName); } public void testHierarchy() { myFixture.configureByFiles(getName() + "/Foo.java", getName() + "/FooImpl.java", getName() + "/Bar.java", getName() + "/Baz.java", getName() + "/Test.java"); rebuildProject(); - CompilerReferenceService.CompilerDirectInheritorInfo directInheritorInfo = getHierarchyUnderForElementCaret(); + CompilerDirectHierarchyInfo directInheritorInfo = getHierarchyForElementUnderCaret(); - Collection inheritors = directInheritorInfo.getDirectInheritors().collect(Collectors.toList()); + Collection inheritors = directInheritorInfo.getHierarchyChildren().collect(Collectors.toList()); assertSize(6, inheritors); for (PsiClass inheritor : inheritors) { if (inheritor instanceof PsiAnonymousClass) { @@ -95,40 +117,54 @@ public class CompilerReferencesTest extends AbstractCompilerAwareTest { } } - Collection candidates = directInheritorInfo.getDirectInheritorCandidates().collect(Collectors.toList()); + Collection candidates = directInheritorInfo.getHierarchyChildCandidates().collect(Collectors.toList()); assertEmpty(candidates); } public void testHierarchyOfLibClass() { myFixture.configureByFiles(getName() + "/Foo.java"); rebuildProject(); - CompilerReferenceService.CompilerDirectInheritorInfo directInheritorInfo = getHierarchyFor(myFixture.getJavaFacade().findClass(CommonClassNames.JAVA_UTIL_LIST)); - PsiClass inheritor = assertOneElement(directInheritorInfo.getDirectInheritors().collect(Collectors.toList())); + CompilerDirectHierarchyInfo directInheritorInfo = getDirectInheritorsFor(myFixture.getJavaFacade().findClass(CommonClassNames.JAVA_UTIL_LIST)); + PsiClass inheritor = assertOneElement(directInheritorInfo.getHierarchyChildren().collect(Collectors.toList())); assertEquals("Foo.ListImpl", inheritor.getQualifiedName()); } - private CompilerReferenceService.CompilerDirectInheritorInfo getHierarchyUnderForElementCaret() { + private CompilerDirectHierarchyInfo getHierarchyForElementUnderCaret() { final PsiElement atCaret = myFixture.getElementAtCaret(); assertNotNull(atCaret); final PsiClass classAtCaret = PsiTreeUtil.getParentOfType(atCaret, PsiClass.class, false); assertNotNull(classAtCaret); - return getHierarchyFor(classAtCaret); + return getDirectInheritorsFor(classAtCaret); } - private CompilerReferenceService.CompilerDirectInheritorInfo getHierarchyFor(PsiClass classAtCaret) { + private CompilerDirectHierarchyInfo getFunctionalExpressionsForElementUnderCaret() { + final PsiElement atCaret = myFixture.getElementAtCaret(); + assertNotNull(atCaret); + final PsiClass classAtCaret = PsiTreeUtil.getParentOfType(atCaret, PsiClass.class, false); + assertNotNull(classAtCaret); + return getFunExpressionsFor(classAtCaret); + } + + private CompilerDirectHierarchyInfo getDirectInheritorsFor(PsiClass classAtCaret) { return CompilerReferenceService.getInstance(myFixture.getProject()).getDirectInheritors(classAtCaret, assertInstanceOf(classAtCaret.getUseScope(), GlobalSearchScope.class), assertInstanceOf(classAtCaret.getUseScope(), GlobalSearchScope.class), - JavaBaseCompilerSearchAdapter.INSTANCE, StdFileTypes.JAVA); } - private Set getReferentFilesForElementUnderCaret(CompilerSearchAdapter adapter) { + private CompilerDirectHierarchyInfo getFunExpressionsFor(PsiClass classAtCaret) { + return CompilerReferenceService.getInstance(myFixture.getProject()).getFunExpressions(classAtCaret, + assertInstanceOf(classAtCaret.getUseScope(), GlobalSearchScope.class), + assertInstanceOf(classAtCaret.getUseScope(), GlobalSearchScope.class), + StdFileTypes.JAVA); + } + + private Set getReferentFilesForElementUnderCaret() { final PsiElement atCaret = myFixture.getElementAtCaret(); assertNotNull(atCaret); final PsiMember memberAtCaret = PsiTreeUtil.getParentOfType(atCaret, PsiMember.class, false); assertNotNull(memberAtCaret); - return ((CompilerReferenceServiceImpl)CompilerReferenceService.getInstance(myFixture.getProject())).getReferentFiles(memberAtCaret, adapter); + return ((CompilerReferenceServiceImpl)CompilerReferenceService.getInstance(myFixture.getProject())).getReferentFiles(memberAtCaret); } @Override diff --git a/jps/javac-ref-scanner-8/src/org/jetbrains/jps/javac/ast/Javac8RefScanner.java b/jps/javac-ref-scanner-8/src/org/jetbrains/jps/javac/ast/Javac8RefScanner.java index a501e2fecd7a..489a2ab6735c 100644 --- a/jps/javac-ref-scanner-8/src/org/jetbrains/jps/javac/ast/Javac8RefScanner.java +++ b/jps/javac-ref-scanner-8/src/org/jetbrains/jps/javac/ast/Javac8RefScanner.java @@ -18,7 +18,7 @@ public class Javac8RefScanner extends JavacTreeRefScanner { JCTree.JCLambda lambda = (JCTree.JCLambda)node; final Type type = lambda.type; final Symbol.TypeSymbol symbol = type.asElement(); - sink.sinkReference(new JavacRefSymbol(symbol, Tree.Kind.LAMBDA_EXPRESSION)); + sink.sinkDeclaration(new JavacRefSymbol(symbol, Tree.Kind.LAMBDA_EXPRESSION)); return super.visitLambdaExpression(node, sink); } @@ -27,7 +27,7 @@ public class Javac8RefScanner extends JavacTreeRefScanner { JCTree.JCMemberReference memberRef = (JCTree.JCMemberReference)node; final Symbol methodSymbol = memberRef.sym; sink.sinkReference(new JavacRefSymbol(methodSymbol, Tree.Kind.IDENTIFIER)); - sink.sinkReference(new JavacRefSymbol(memberRef.type.asElement(), Tree.Kind.MEMBER_REFERENCE)); + sink.sinkDeclaration(new JavacRefSymbol(memberRef.type.asElement(), Tree.Kind.MEMBER_REFERENCE)); return super.visitMemberReference(node, sink); } } diff --git a/jps/javac-ref-scanner-8/testData/referenceIndex/lambda/initialIndex.txt b/jps/javac-ref-scanner-8/testData/referenceIndex/lambda/initialIndex.txt index 70c68c529132..14c71e826610 100644 --- a/jps/javac-ref-scanner-8/testData/referenceIndex/lambda/initialIndex.txt +++ b/jps/javac-ref-scanner-8/testData/referenceIndex/lambda/initialIndex.txt @@ -1,14 +1,15 @@ Backward Hierarchy: java.lang.Object -> Lambda +java.lang.Runnable -> fun_expr(id=0) Backward References: Lambda in Lambda Lambda.(0) in Lambda Lambda.main(1) in Lambda -fun_expr(java.lang.Runnable) in Lambda java.lang.Object.(0) in Lambda java.lang.String in Lambda java.lang.Thread in Lambda Class Definitions: -Lambda in Lambda \ No newline at end of file +Lambda in Lambda +fun_expr(id=0) in Lambda \ No newline at end of file diff --git a/jps/javac-ref-scanner-8/testData/referenceIndex/methodReference/initialIndex.txt b/jps/javac-ref-scanner-8/testData/referenceIndex/methodReference/initialIndex.txt index 3bf4cae03246..6582ae188fcd 100644 --- a/jps/javac-ref-scanner-8/testData/referenceIndex/methodReference/initialIndex.txt +++ b/jps/javac-ref-scanner-8/testData/referenceIndex/methodReference/initialIndex.txt @@ -1,11 +1,11 @@ Backward Hierarchy: java.lang.Object -> MethodReference +java.lang.Runnable -> fun_expr(id=0) Backward References: MethodReference in MethodReference MethodReference.(0) in MethodReference MethodReference.main(1) in MethodReference -fun_expr(java.lang.Runnable) in MethodReference java.lang.Object.(0) in MethodReference java.lang.String in MethodReference java.lang.Thread in MethodReference @@ -13,4 +13,5 @@ java.util.Collections in MethodReference java.util.Collections.emptyList(0) in MethodReference Class Definitions: -MethodReference in MethodReference \ No newline at end of file +MethodReference in MethodReference +fun_expr(id=0) in MethodReference \ No newline at end of file diff --git a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexWriter.java b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexWriter.java index a66969609754..51fa3972d9e5 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexWriter.java +++ b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexWriter.java @@ -18,9 +18,12 @@ package org.jetbrains.jps.backwardRefs; import com.intellij.util.Function; import com.intellij.util.SystemProperties; import com.intellij.util.containers.ContainerUtil; +import com.sun.source.tree.Tree; +import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Symbol; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.builders.java.JavaBuilderUtil; import org.jetbrains.jps.builders.storage.BuildDataCorruptedException; import org.jetbrains.jps.incremental.CompileContext; @@ -37,6 +40,8 @@ import java.util.Collection; import java.util.List; import java.util.Set; +import static com.sun.tools.javac.code.Flags.PRIVATE; + public class BackwardReferenceIndexWriter { public static final String PROP_KEY = "ref.index.builder"; @@ -89,8 +94,8 @@ public class BackwardReferenceIndexWriter { return enumeratePath(file.getName()); } - synchronized LightUsage.LightClassUsage asClassUsage(Symbol name) { - return new LightUsage.LightClassUsage(myIndex.getByteSeqEum().enumerate(LightUsage.bytes(name))); + synchronized LightRef.JavaLightClassRef asClassUsage(Symbol name) { + return new LightRef.JavaLightClassRef(myIndex.getByteSeqEum().enumerate(bytes(name))); } synchronized void processDeletedFiles(Collection paths) { @@ -98,22 +103,22 @@ public class BackwardReferenceIndexWriter { final int deletedFileId = enumeratePath(path); //remove from reference maps - final Collection refs = myIndex.getReferenceMap().get(deletedFileId); + final Collection refs = myIndex.getReferenceMap().get(deletedFileId); if (refs != null) { - for (LightUsage ref : refs) { + for (LightRef ref : refs) { myIndex.getBackwardReferenceMap().removeFrom(ref, deletedFileId); } } myIndex.getReferenceMap().remove(deletedFileId); //remove from definition & hierarchy maps - final Collection definedClasses = myIndex.getClassDefinitionMap().get(deletedFileId); + final Collection definedClasses = myIndex.getClassDefinitionMap().get(deletedFileId); removeClassesFromHierarchy(deletedFileId, definedClasses); myIndex.getClassDefinitionMap().remove(deletedFileId); } } - synchronized void writeClassDefinitions(int fileId, Collection classes) { + synchronized void writeClassDefinitions(int fileId, Collection classes) { if (myRebuild) { directlyWriteClassDefinitions(fileId, classes); } else { @@ -121,12 +126,12 @@ public class BackwardReferenceIndexWriter { } } - private void updateClassDefinitions(int fileId, Collection classes) { - final Collection oldDefs = myIndex.getClassDefinitionMap().get(fileId); - final Collection oldDefsCopy = oldDefs == null ? null : new THashSet(oldDefs); + private void updateClassDefinitions(int fileId, Collection classes) { + final Collection oldDefs = myIndex.getClassDefinitionMap().get(fileId); + final Collection oldDefsCopy = oldDefs == null ? null : new THashSet(oldDefs); myIndex.getClassDefinitionMap().replace(fileId, classes); - for (LightUsage aClass : classes) { + for (LightRef aClass : classes) { if (oldDefsCopy == null || !oldDefsCopy.remove(aClass)) { myIndex.getBackwardClassDefinitionMap().put(aClass, fileId); } @@ -135,24 +140,24 @@ public class BackwardReferenceIndexWriter { removeClassesFromHierarchy(fileId, oldDefsCopy); } - private void directlyWriteClassDefinitions(int fileId, Collection classes) { + private void directlyWriteClassDefinitions(int fileId, Collection classes) { myIndex.getClassDefinitionMap().put(fileId, classes); - for (LightUsage aClass : classes) { + for (LightRef aClass : classes) { myIndex.getBackwardClassDefinitionMap().put(aClass, fileId); } } synchronized void writeReferences(int fileId, Collection refs) { final ByteArrayEnumerator byteSeqEum = myIndex.getByteSeqEum(); - final List usages = ContainerUtil.mapNotNull(refs, new Function() { + final List usages = ContainerUtil.mapNotNull(refs, new Function() { @Override - public LightUsage fun(JavacRefSymbol symbol) { - return LightUsage.fromSymbol(symbol, byteSeqEum); + public LightRef fun(JavacRefSymbol symbol) { + return fromSymbol(symbol, byteSeqEum); } }); if (myRebuild) { - for (LightUsage usage : usages) { + for (LightRef usage : usages) { myIndex.getBackwardReferenceMap().put(usage, fileId); myIndex.getReferenceMap().put(fileId, usage); } @@ -162,10 +167,10 @@ public class BackwardReferenceIndexWriter { } } - private void updateReferenceIndicesIncrementally(int fileId, Collection usages) { - final Collection rawOldUsages = myIndex.getReferenceMap().get(fileId); - Collection oldUsages = rawOldUsages == null ? null : new ArrayList(rawOldUsages); - for (LightUsage usage : usages) { + private void updateReferenceIndicesIncrementally(int fileId, Collection usages) { + final Collection rawOldUsages = myIndex.getReferenceMap().get(fileId); + Collection oldUsages = rawOldUsages == null ? null : new ArrayList(rawOldUsages); + for (LightRef usage : usages) { if (oldUsages == null || !oldUsages.remove(usage)) { myIndex.getBackwardReferenceMap().put(usage, fileId); myIndex.getReferenceMap().put(fileId, usage); @@ -173,13 +178,13 @@ public class BackwardReferenceIndexWriter { } if (oldUsages != null && !oldUsages.isEmpty()) { myIndex.getReferenceMap().removeAll(fileId, oldUsages); - for (LightUsage usage : oldUsages) { + for (LightRef usage : oldUsages) { myIndex.getBackwardReferenceMap().removeFrom(usage, fileId); } } } - synchronized void writeHierarchy(int fileId, LightUsage.LightClassUsage aClass, LightUsage.LightClassUsage[] supers) { + synchronized void writeHierarchy(int fileId, LightRef aClass, LightRef.JavaLightClassRef... supers) { CompilerBackwardReferenceIndex.LightDefinition def = new CompilerBackwardReferenceIndex.LightDefinition(aClass, fileId); if (myRebuild) { directlyWriteHierarchyIndices(def, supers); @@ -198,17 +203,17 @@ public class BackwardReferenceIndexWriter { } } - private void directlyWriteHierarchyIndices(CompilerBackwardReferenceIndex.LightDefinition classId, LightUsage.LightClassUsage[] superIds) { - for (LightUsage.LightClassUsage superId : superIds) { + private void directlyWriteHierarchyIndices(CompilerBackwardReferenceIndex.LightDefinition classId, LightRef.JavaLightClassRef[] superIds) { + for (LightRef.JavaLightClassRef superId : superIds) { myIndex.getBackwardHierarchyMap().put(superId, classId); myIndex.getHierarchyMap().put(classId, superId); } } - private void updateHierarchyIndicesIncrementally(final CompilerBackwardReferenceIndex.LightDefinition classId, LightUsage.LightClassUsage[] superIds) { - final Collection rawOldSupers = myIndex.getHierarchyMap().get(classId); - Set oldSuperClasses = rawOldSupers == null ? null : new THashSet(rawOldSupers); - for (LightUsage.LightClassUsage superId: superIds) { + private void updateHierarchyIndicesIncrementally(final CompilerBackwardReferenceIndex.LightDefinition classId, LightRef.JavaLightClassRef[] superIds) { + final Collection rawOldSupers = myIndex.getHierarchyMap().get(classId); + Set oldSuperClasses = rawOldSupers == null ? null : new THashSet(rawOldSupers); + for (LightRef.JavaLightClassRef superId: superIds) { if (oldSuperClasses == null || !oldSuperClasses.remove(superId)) { myIndex.getBackwardHierarchyMap().put(superId, classId); myIndex.getHierarchyMap().put(classId, superId); @@ -216,22 +221,22 @@ public class BackwardReferenceIndexWriter { } if (oldSuperClasses != null && !oldSuperClasses.isEmpty()) { myIndex.getHierarchyMap().removeAll(classId, oldSuperClasses); - for (LightUsage anOldClass : oldSuperClasses) { + for (LightRef anOldClass : oldSuperClasses) { myIndex.getBackwardHierarchyMap().put(anOldClass, classId); } } } - private void removeClassesFromHierarchy(int deletedFileId, Collection definedClasses) { + private void removeClassesFromHierarchy(int deletedFileId, Collection definedClasses) { if (definedClasses != null) { - for (LightUsage aClass : definedClasses) { + for (LightRef aClass : definedClasses) { myIndex.getBackwardClassDefinitionMap().removeFrom(aClass, deletedFileId); final CompilerBackwardReferenceIndex.LightDefinition def = new CompilerBackwardReferenceIndex.LightDefinition(aClass, deletedFileId); - final Collection superClasses = myIndex.getHierarchyMap().get(def); + final Collection superClasses = myIndex.getHierarchyMap().get(def); if (superClasses != null) { - for (LightUsage superClass : superClasses) { + for (LightRef superClass : superClasses) { myIndex.getBackwardHierarchyMap().removeFrom(superClass, def); } } @@ -239,6 +244,52 @@ public class BackwardReferenceIndexWriter { } } } + + static byte[] bytes(Symbol symbol) { + return symbol.flatName().toUtf(); + } + + @Nullable + static LightRef fromSymbol(JavacRefSymbol refSymbol, ByteArrayEnumerator byteArrayEnumerator) { + Symbol symbol = refSymbol.getSymbol(); + final Tree.Kind kind = refSymbol.getPlaceKind(); + if (symbol instanceof Symbol.ClassSymbol) { + if (!isPrivate(symbol) && !isAnonymous(symbol)) { + return new LightRef.JavaLightClassRef(id(symbol, byteArrayEnumerator)); + } + } + else { + Symbol owner = symbol.owner; + if (isPrivate(symbol)) { + return null; + } + if (symbol instanceof Symbol.VarSymbol) { + return new LightRef.JavaLightFieldRef(id(owner, byteArrayEnumerator), id(symbol, byteArrayEnumerator)); + } + else if (symbol instanceof Symbol.MethodSymbol) { + int paramCount = ((Symbol.MethodSymbol)symbol).type.getParameterTypes().size(); + return new LightRef.JavaLightMethodRef(id(owner, byteArrayEnumerator), id(symbol, byteArrayEnumerator), paramCount); + } + else { + throw new AssertionError("unexpected symbol: " + symbol + " class: " + symbol.getClass() + " kind: " + kind); + } + } + return null; + } + + // JDK-6 has no Symbol.isPrivate() method + private static boolean isPrivate(Symbol symbol) { + return (symbol.flags() & Flags.AccessFlags) == PRIVATE; + } + + // JDK-6 has no Symbol.isAnonymous() method + private static boolean isAnonymous(Symbol symbol) { + return symbol.name.isEmpty(); + } + + private static int id(Symbol symbol, ByteArrayEnumerator byteArrayEnumerator) { + return byteArrayEnumerator.enumerate(bytes(symbol)); + } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceRegistrar.java b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceRegistrar.java index 285969430a0c..550686a4b92f 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceRegistrar.java +++ b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceRegistrar.java @@ -23,13 +23,28 @@ import org.jetbrains.jps.javac.ast.api.JavacRefSymbol; import javax.tools.*; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import java.util.Set; public class BackwardReferenceRegistrar implements JavacFileReferencesRegistrar { private static final Symbol[] EMPTY_SYMBOL_ARRAY = new Symbol[0]; + private static final Tree.Kind LAMBDA_EXPRESSION; + private static final Tree.Kind MEMBER_REFERENCE; + + static { + Tree.Kind lambdaExpression = null; + Tree.Kind memberReference = null; + try { + lambdaExpression = Tree.Kind.valueOf("LAMBDA_EXPRESSION"); + memberReference = Tree.Kind.valueOf("MEMBER_REFERENCE"); + } + catch (IllegalArgumentException ignored) { + } + LAMBDA_EXPRESSION = lambdaExpression; + MEMBER_REFERENCE = memberReference; + } + private BackwardReferenceIndexWriter myWriter; @Override @@ -44,10 +59,11 @@ public class BackwardReferenceRegistrar implements JavacFileReferencesRegistrar } @Override - public void registerFile(JavaFileObject file, Set refs, Collection defs) { + public void registerFile(JavaFileObject file, Set refs, List defs) { final int fileId = myWriter.enumerateFile(file); + int funExprId = 0; - final List definedClasses = new ArrayList(defs.size()); + final List definitions = new ArrayList(defs.size()); for (JavacRefSymbol def : defs) { Tree.Kind kind = def.getPlaceKind(); if (kind == Tree.Kind.CLASS) { @@ -68,24 +84,29 @@ public class BackwardReferenceRegistrar implements JavacFileReferencesRegistrar supers[i++] = anInterface.asElement(); } - - final LightUsage.LightClassUsage aClass = myWriter.asClassUsage(sym); - definedClasses.add(aClass); + final LightRef.JavaLightClassRef aClass = myWriter.asClassUsage(sym); + definitions.add(aClass); if (supers.length != 0) { - final LightUsage.LightClassUsage[] superIds = new LightUsage.LightClassUsage[supers.length]; + final LightRef.JavaLightClassRef[] superIds = new LightRef.JavaLightClassRef[supers.length]; for (int j = 0; j < supers.length; j++) { superIds[j] = myWriter.asClassUsage(supers[j]); } myWriter.writeHierarchy(fileId, aClass, superIds); } - + } + else if (kind == LAMBDA_EXPRESSION || kind == MEMBER_REFERENCE) { + final LightRef.JavaLightClassRef functionalType = myWriter.asClassUsage(def.getSymbol()); + int id = funExprId++; + LightRef.JavaLightFunExprDef result = new LightRef.JavaLightFunExprDef(id); + definitions.add(result); + myWriter.writeHierarchy(fileId, result, functionalType); } } - myWriter.writeClassDefinitions(fileId, definedClasses); + myWriter.writeClassDefinitions(fileId, definitions); myWriter.writeReferences(fileId, refs); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/ByteArrayEnumerator.java b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/ByteArrayEnumerator.java index 6b0e38cfdb65..86efeb615c39 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/ByteArrayEnumerator.java +++ b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/ByteArrayEnumerator.java @@ -15,7 +15,9 @@ */ package org.jetbrains.jps.backwardRefs; +import com.intellij.util.ObjectUtils; import com.intellij.util.io.*; +import com.sun.tools.javac.util.Convert; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.builders.storage.BuildDataCorruptedException; @@ -64,6 +66,15 @@ public class ByteArrayEnumerator extends PersistentEnumeratorDelegate { if (myCache != null) myCache.close(); } + @NotNull + public String getName(int idx) { + try { + return Convert.utf2string(ObjectUtils.notNull(valueOf(idx))); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } private static class ByteSequenceDataExternalizer implements KeyDescriptor, DifferentSerializableBytesImplyNonEqualityPolicy { private static final ByteSequenceDataExternalizer INSTANCE = new ByteSequenceDataExternalizer(); diff --git a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/CompilerBackwardReferenceIndex.java b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/CompilerBackwardReferenceIndex.java index f603863a38cb..e587eb0586e2 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/CompilerBackwardReferenceIndex.java +++ b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/CompilerBackwardReferenceIndex.java @@ -45,14 +45,14 @@ public class CompilerBackwardReferenceIndex { private final static String BACK_CLASS_DEF_TAB = "back.class.def.tab"; public static final String VERSION_FILE = ".version"; - private final IntObjectPersistentMultiMaplet myReferenceMap; - private final ObjectObjectPersistentMultiMaplet myHierarchyMap; + private final IntObjectPersistentMultiMaplet myReferenceMap; + private final ObjectObjectPersistentMultiMaplet myHierarchyMap; - private final ObjectObjectPersistentMultiMaplet myBackwardReferenceMap; - private final ObjectObjectPersistentMultiMaplet myBackwardHierarchyMap; + private final ObjectObjectPersistentMultiMaplet myBackwardReferenceMap; + private final ObjectObjectPersistentMultiMaplet myBackwardHierarchyMap; - private final ObjectObjectPersistentMultiMaplet myBackwardClassDefinitionMap; - private final IntObjectPersistentMultiMaplet myClassDefinitionMap; + private final ObjectObjectPersistentMultiMaplet myBackwardClassDefinitionMap; + private final IntObjectPersistentMultiMaplet myClassDefinitionMap; private final ByteArrayEnumerator myNameEnumerator; private final PersistentStringEnumerator myFilePathEnumerator; @@ -76,22 +76,22 @@ public class CompilerBackwardReferenceIndex { } }; - final KeyDescriptor lightUsageDescriptor = LightUsage.createDescriptor(); + final KeyDescriptor lightUsageDescriptor = new LightRefDescriptor(); final KeyDescriptor defDescriptor = LightDefinition.createDescriptor(lightUsageDescriptor); - myBackwardReferenceMap = new ObjectObjectPersistentMultiMaplet(new File(myIndicesDir, BACK_USAGES_TAB), - lightUsageDescriptor, - EnumeratorIntegerDescriptor.INSTANCE, - new CollectionFactory() { + myBackwardReferenceMap = new ObjectObjectPersistentMultiMaplet(new File(myIndicesDir, BACK_USAGES_TAB), + lightUsageDescriptor, + EnumeratorIntegerDescriptor.INSTANCE, + new CollectionFactory() { @Override public Collection create() { return new THashSet(); } }); - myBackwardHierarchyMap = new ObjectObjectPersistentMultiMaplet(new File(myIndicesDir, BACK_HIERARCHY_TAB), - lightUsageDescriptor, - defDescriptor, - new CollectionFactory() { + myBackwardHierarchyMap = new ObjectObjectPersistentMultiMaplet(new File(myIndicesDir, BACK_HIERARCHY_TAB), + lightUsageDescriptor, + defDescriptor, + new CollectionFactory() { @Override public Collection create() { return new THashSet(); @@ -99,38 +99,38 @@ public class CompilerBackwardReferenceIndex { }); - myReferenceMap = new IntObjectPersistentMultiMaplet(new File(myIndicesDir, USAGES_TAB), - EnumeratorIntegerDescriptor.INSTANCE, - lightUsageDescriptor, new CollectionFactory() { + myReferenceMap = new IntObjectPersistentMultiMaplet(new File(myIndicesDir, USAGES_TAB), + EnumeratorIntegerDescriptor.INSTANCE, + lightUsageDescriptor, new CollectionFactory() { @Override - public Collection create() { - return new THashSet(); + public Collection create() { + return new THashSet(); } }); - myHierarchyMap = new ObjectObjectPersistentMultiMaplet(new File(myIndicesDir, HIERARCHY_TAB), - defDescriptor, - lightUsageDescriptor, - new CollectionFactory() { + myHierarchyMap = new ObjectObjectPersistentMultiMaplet(new File(myIndicesDir, HIERARCHY_TAB), + defDescriptor, + lightUsageDescriptor, + new CollectionFactory() { @Override - public Collection create() { - return new THashSet(); + public Collection create() { + return new THashSet(); } }); - myClassDefinitionMap = new IntObjectPersistentMultiMaplet(new File(myIndicesDir, CLASS_DEF_TAB), - EnumeratorIntegerDescriptor.INSTANCE, - lightUsageDescriptor, - new CollectionFactory() { + myClassDefinitionMap = new IntObjectPersistentMultiMaplet(new File(myIndicesDir, CLASS_DEF_TAB), + EnumeratorIntegerDescriptor.INSTANCE, + lightUsageDescriptor, + new CollectionFactory() { @Override - public Collection create() { - return new THashSet(); + public Collection create() { + return new THashSet(); } }); - myBackwardClassDefinitionMap = new ObjectObjectPersistentMultiMaplet(new File(myIndicesDir, BACK_CLASS_DEF_TAB), - lightUsageDescriptor, - EnumeratorIntegerDescriptor.INSTANCE, - new CollectionFactory() { + myBackwardClassDefinitionMap = new ObjectObjectPersistentMultiMaplet(new File(myIndicesDir, BACK_CLASS_DEF_TAB), + lightUsageDescriptor, + EnumeratorIntegerDescriptor.INSTANCE, + new CollectionFactory() { @Override public Collection create() { return new THashSet(); @@ -146,32 +146,32 @@ public class CompilerBackwardReferenceIndex { } @NotNull - public ObjectObjectPersistentMultiMaplet getBackwardReferenceMap() { + public ObjectObjectPersistentMultiMaplet getBackwardReferenceMap() { return myBackwardReferenceMap; } @NotNull - public ObjectObjectPersistentMultiMaplet getBackwardHierarchyMap() { + public ObjectObjectPersistentMultiMaplet getBackwardHierarchyMap() { return myBackwardHierarchyMap; } @NotNull - public IntObjectPersistentMultiMaplet getReferenceMap() { + public IntObjectPersistentMultiMaplet getReferenceMap() { return myReferenceMap; } @NotNull - public ObjectObjectPersistentMultiMaplet getHierarchyMap() { + public ObjectObjectPersistentMultiMaplet getHierarchyMap() { return myHierarchyMap; } @NotNull - public ObjectObjectPersistentMultiMaplet getBackwardClassDefinitionMap() { + public ObjectObjectPersistentMultiMaplet getBackwardClassDefinitionMap() { return myBackwardClassDefinitionMap; } @NotNull - public IntObjectPersistentMultiMaplet getClassDefinitionMap() { + public IntObjectPersistentMultiMaplet getClassDefinitionMap() { return myClassDefinitionMap; } @@ -247,15 +247,15 @@ public class CompilerBackwardReferenceIndex { } public static class LightDefinition { - private final LightUsage myUsage; + private final LightRef myUsage; private final int myFileId; - LightDefinition(LightUsage usage, int id) { + LightDefinition(LightRef usage, int id) { myUsage = usage; myFileId = id; } - public LightUsage getUsage() { + public LightRef getRef() { return myUsage; } @@ -281,7 +281,7 @@ public class CompilerBackwardReferenceIndex { return myUsage.hashCode(); } - private static KeyDescriptor createDescriptor(final DataExternalizer usageDataExternalizer) { + private static KeyDescriptor createDescriptor(final DataExternalizer usageDataExternalizer) { return new KeyDescriptor() { @Override public int getHashCode(LightDefinition value) { @@ -295,7 +295,7 @@ public class CompilerBackwardReferenceIndex { @Override public void save(@NotNull DataOutput out, LightDefinition value) throws IOException { - usageDataExternalizer.save(out, value.getUsage()); + usageDataExternalizer.save(out, value.getRef()); EnumeratorIntegerDescriptor.INSTANCE.save(out, value.getFileId()); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/LightRef.java b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/LightRef.java new file mode 100644 index 000000000000..3b94591bab97 --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/LightRef.java @@ -0,0 +1,263 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.jps.backwardRefs; + +import com.intellij.util.io.DataInputOutputUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.builders.java.dependencyView.RW; +import org.jetbrains.jps.builders.storage.BuildDataCorruptedException; + +import java.io.DataOutput; +import java.io.IOException; + +public interface LightRef extends RW.Savable { + LightRef[] EMPTY_ARRAY = new LightRef[0]; + + byte CLASS_MARKER = 0x0; + byte METHOD_MARKER = 0x1; + byte FIELD_MARKER = 0x2; + byte FUN_EXPR_MARKER = 0x3; + + LightRef override(int newOwner); + + interface NamedLightRef extends LightRef { + int getName(); + } + + interface LightClassHierarchyElementDef extends NamedLightRef { + } + + interface LightFunExprDef extends LightRef { + int getId(); + } + + interface LightMember extends NamedLightRef { + @NotNull + LightClassHierarchyElementDef getOwner(); + } + + class JavaLightMethodRef implements LightMember { + private final int myOwner; + private final int myName; + private final int myParameterCount; + + public JavaLightMethodRef(int owner, int name, int parameterCount) { + myOwner = owner; + myName = name; + myParameterCount = parameterCount; + } + + public int getName() { + return myName; + } + + @Override + public LightRef override(int newOwner) { + return new JavaLightMethodRef(newOwner, myName, myParameterCount); + } + + public int getParameterCount() { + return myParameterCount; + } + + @Override + @NotNull + public LightClassHierarchyElementDef getOwner() { + return new JavaLightClassRef(myOwner); + } + + @Override + public void save(DataOutput out) { + try { + out.writeByte(METHOD_MARKER); + DataInputOutputUtil.writeINT(out, myOwner); + DataInputOutputUtil.writeINT(out, getName()); + DataInputOutputUtil.writeINT(out, getParameterCount()); + } + catch (IOException e) { + throw new BuildDataCorruptedException(e); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + JavaLightMethodRef usage = (JavaLightMethodRef)o; + + if (myOwner != usage.myOwner) return false; + if (myName != usage.myName) return false; + if (myParameterCount != usage.myParameterCount) return false; + + return true; + } + + @Override + public int hashCode() { + int result = myName; + result = 31 * result + myParameterCount; + result = 31 * result + myOwner; + return result; + } + } + + class JavaLightFieldRef implements LightMember { + private final int myOwner; + private final int myName; + + public JavaLightFieldRef(int owner, int name) { + myOwner = owner; + myName = name; + } + + @Override + public int getName() { + return myName; + } + + @Override + public LightRef override(int newOwner) { + return new JavaLightFieldRef(newOwner, myName); + } + + @NotNull + @Override + public LightClassHierarchyElementDef getOwner() { + return new JavaLightClassRef(myOwner); + } + + @Override + public void save(DataOutput out) { + try { + out.writeByte(FIELD_MARKER); + DataInputOutputUtil.writeINT(out, myOwner); + DataInputOutputUtil.writeINT(out, getName()); + } + catch (IOException e) { + throw new BuildDataCorruptedException(e); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + JavaLightFieldRef usage = (JavaLightFieldRef)o; + + if (myOwner != usage.myOwner) return false; + if (myName != usage.myName) return false; + + return true; + } + + @Override + public int hashCode() { + return myName + 31 * myOwner; + } + } + + class JavaLightClassRef implements LightClassHierarchyElementDef { + private final int myName; + + public JavaLightClassRef(int name) { + myName = name; + } + + @Override + public int getName() { + return myName; + } + + @Override + public LightRef override(int newOwner) { + return new JavaLightClassRef(newOwner); + } + + @Override + public void save(DataOutput out) { + try { + out.writeByte(CLASS_MARKER); + DataInputOutputUtil.writeINT(out, getName()); + } + catch (IOException e) { + throw new BuildDataCorruptedException(e); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + JavaLightClassRef usage = (JavaLightClassRef)o; + + if (myName != usage.myName) return false; + + return true; + } + + @Override + public int hashCode() { + return myName; + } + } + + class JavaLightFunExprDef implements LightFunExprDef { + private final int myId; + + public JavaLightFunExprDef(int id) { + myId = id; + } + + @Override + public int getId() { + return myId; + } + + @Override + public LightRef override(int newOwner) { + throw new UnsupportedOperationException(); + } + + @Override + public void save(DataOutput out) { + try { + out.writeByte(FUN_EXPR_MARKER); + DataInputOutputUtil.writeINT(out, getId()); + } + catch (IOException e) { + throw new BuildDataCorruptedException(e); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + JavaLightFunExprDef usage = (JavaLightFunExprDef)o; + return myId == usage.myId; + } + + @Override + public int hashCode() { + return myId; + } + + } +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/LightRefDescriptor.java b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/LightRefDescriptor.java new file mode 100644 index 000000000000..9734b2f66769 --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/LightRefDescriptor.java @@ -0,0 +1,60 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.jps.backwardRefs; + +import com.intellij.util.io.DataInputOutputUtil; +import com.intellij.util.io.DifferentSerializableBytesImplyNonEqualityPolicy; +import com.intellij.util.io.KeyDescriptor; +import org.jetbrains.annotations.NotNull; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import static org.jetbrains.jps.backwardRefs.LightRef.*; + +final class LightRefDescriptor implements KeyDescriptor, DifferentSerializableBytesImplyNonEqualityPolicy { + @Override + public int getHashCode(LightRef value) { + return value.hashCode(); + } + + @Override + public boolean isEqual(LightRef val1, LightRef val2) { + return val1.equals(val2); + } + + @Override + public void save(@NotNull DataOutput out, LightRef value) throws IOException { + value.save(out); + } + + @Override + public LightRef read(@NotNull DataInput in) throws IOException { + final byte type = in.readByte(); + switch (type) { + case CLASS_MARKER: + return new JavaLightClassRef(DataInputOutputUtil.readINT(in)); + case METHOD_MARKER: + return new JavaLightMethodRef(DataInputOutputUtil.readINT(in), DataInputOutputUtil.readINT(in), DataInputOutputUtil.readINT(in)); + case FIELD_MARKER: + return new JavaLightFieldRef(DataInputOutputUtil.readINT(in), DataInputOutputUtil.readINT(in)); + case FUN_EXPR_MARKER: + return new JavaLightFunExprDef(DataInputOutputUtil.readINT(in)); + } + throw new AssertionError(); + } +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/LightUsage.java b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/LightUsage.java deleted file mode 100644 index 589e523b4e3e..000000000000 --- a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/LightUsage.java +++ /dev/null @@ -1,380 +0,0 @@ -/* - * Copyright 2000-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jetbrains.jps.backwardRefs; - -import com.intellij.util.io.DataInputOutputUtil; -import com.intellij.util.io.KeyDescriptor; -import com.sun.source.tree.Tree; -import com.sun.tools.javac.code.Flags; -import com.sun.tools.javac.code.Symbol; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.jps.builders.java.dependencyView.RW; -import org.jetbrains.jps.builders.storage.BuildDataCorruptedException; -import org.jetbrains.jps.javac.ast.api.JavacRefSymbol; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -import static com.sun.tools.javac.code.Flags.PRIVATE; - -public abstract class LightUsage implements RW.Savable { - private final static byte CLASS_MARKER = 0x0; - private final static byte METHOD_MARKER = 0x1; - private final static byte FIELD_MARKER = 0x2; - private final static byte FUN_EXPR_MARKER = 0x3; - - static final Tree.Kind LAMBDA_EXPRESSION; - static final Tree.Kind MEMBER_REFERENCE; - - static { - Tree.Kind lambdaExpression = null; - Tree.Kind memberReference = null; - try { - lambdaExpression = Tree.Kind.valueOf("LAMBDA_EXPRESSION"); - memberReference = Tree.Kind.valueOf("MEMBER_REFERENCE"); - } - catch (IllegalArgumentException ignored) { - } - LAMBDA_EXPRESSION = lambdaExpression; - MEMBER_REFERENCE = memberReference; - } - - public abstract int getName(); - - @NotNull - public abstract LightUsage override(LightUsage overriderClass); - - @NotNull - public abstract LightUsage getOwner(); - - public static class LightMethodUsage extends LightUsage { - private final int myOwner; - private final int myName; - private final int myParameterCount; - - public LightMethodUsage(int owner, int name, int parameterCount) { - myOwner = owner; - myName = name; - myParameterCount = parameterCount; - } - - @Override - public int getName() { - return myName; - } - - public int getParameterCount() { - return myParameterCount; - } - - @Override - @NotNull - public LightUsage getOwner() { - return new LightClassUsage(myOwner); - } - - @Override - public void save(DataOutput out) { - try { - out.writeByte(METHOD_MARKER); - DataInputOutputUtil.writeINT(out, myOwner); - DataInputOutputUtil.writeINT(out, getName()); - DataInputOutputUtil.writeINT(out, getParameterCount()); - } - catch (IOException e) { - throw new BuildDataCorruptedException(e); - } - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - LightMethodUsage usage = (LightMethodUsage)o; - - if (myOwner != usage.myOwner) return false; - if (myName != usage.myName) return false; - if (myParameterCount != usage.myParameterCount) return false; - - return true; - } - - @Override - public int hashCode() { - int result = myName; - result = 31 * result + myParameterCount; - result = 31 * result + myOwner; - return result; - } - - @NotNull - @Override - public LightMethodUsage override(LightUsage overriderClass) { - return new LightMethodUsage(overriderClass.getName(), getName(), getParameterCount()); - } - } - - public static class LightFieldUsage extends LightUsage { - private final int myOwner; - private final int myName; - - public LightFieldUsage(int owner, int name) { - myOwner = owner; - myName = name; - } - - @Override - public int getName() { - return myName; - } - - @NotNull - @Override - public LightUsage getOwner() { - return new LightClassUsage(myOwner); - } - - @Override - public void save(DataOutput out) { - try { - out.writeByte(FIELD_MARKER); - DataInputOutputUtil.writeINT(out, myOwner); - DataInputOutputUtil.writeINT(out, getName()); - } - catch (IOException e) { - throw new BuildDataCorruptedException(e); - } - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - LightFieldUsage usage = (LightFieldUsage)o; - - if (myOwner != usage.myOwner) return false; - if (myName != usage.myName) return false; - - return true; - } - - @Override - public int hashCode() { - return myName + 31 * myOwner; - } - - @NotNull - @Override - public LightFieldUsage override(LightUsage overriderClass) { - return new LightFieldUsage(overriderClass.getName(), getName()); - } - - } - - public static class LightClassUsage extends LightUsage { - private final int myName; - - public LightClassUsage(int name) { - myName = name; - } - - @Override - public int getName() { - return myName; - } - - @NotNull - @Override - public LightClassUsage override(LightUsage overriderClass) { - return (LightClassUsage)overriderClass; - } - - @NotNull - @Override - public LightUsage getOwner() { - return this; - } - - - @Override - public void save(DataOutput out) { - try { - out.writeByte(CLASS_MARKER); - DataInputOutputUtil.writeINT(out, getName()); - } - catch (IOException e) { - throw new BuildDataCorruptedException(e); - } - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - LightClassUsage usage = (LightClassUsage)o; - - if (myName != usage.myName) return false; - - return true; - } - - @Override - public int hashCode() { - return myName; - } - } - - public static class LightFunExprUsage extends LightUsage { - private final int myName; - - public LightFunExprUsage(int name) { - myName = name; - } - - @NotNull - @Override - public LightFunExprUsage override(LightUsage overriderClass) { - throw new UnsupportedOperationException(); - } - - @NotNull - @Override - public LightUsage getOwner() { - throw new UnsupportedOperationException(); - } - - @Override - public int getName() { - return myName; - } - - @Override - public void save(DataOutput out) { - try { - out.writeByte(FUN_EXPR_MARKER); - DataInputOutputUtil.writeINT(out, getName()); - } - catch (IOException e) { - throw new BuildDataCorruptedException(e); - } - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - LightFunExprUsage usage = (LightFunExprUsage)o; - - if (myName != usage.myName) return false; - - return true; - } - - @Override - public int hashCode() { - return myName; - } - } - - static KeyDescriptor createDescriptor() { - return new KeyDescriptor() { - @Override - public int getHashCode(LightUsage value) { - return value.hashCode(); - } - - @Override - public boolean isEqual(LightUsage val1, LightUsage val2) { - return val1.equals(val2); - } - - @Override - public void save(@NotNull DataOutput out, LightUsage value) throws IOException { - value.save(out); - } - - @Override - public LightUsage read(@NotNull DataInput in) throws IOException { - final byte type = in.readByte(); - switch (type) { - case CLASS_MARKER: - return new LightClassUsage(DataInputOutputUtil.readINT(in)); - case METHOD_MARKER: - return new LightMethodUsage(DataInputOutputUtil.readINT(in), DataInputOutputUtil.readINT(in), DataInputOutputUtil.readINT(in)); - case FIELD_MARKER: - return new LightFieldUsage(DataInputOutputUtil.readINT(in), DataInputOutputUtil.readINT(in)); - case FUN_EXPR_MARKER: - return new LightFunExprUsage(DataInputOutputUtil.readINT(in)); - } - throw new AssertionError(); - } - }; - } - - static byte[] bytes(Symbol symbol) { - return symbol.flatName().toUtf(); - } - - @Nullable - static LightUsage fromSymbol(JavacRefSymbol refSymbol, ByteArrayEnumerator byteArrayEnumerator) { - Symbol symbol = refSymbol.getSymbol(); - final Tree.Kind kind = refSymbol.getPlaceKind(); - if (symbol instanceof Symbol.ClassSymbol) { - if (kind == LAMBDA_EXPRESSION || kind == MEMBER_REFERENCE) { - return new LightFunExprUsage(id(symbol, byteArrayEnumerator)); - } else if (!isPrivate(symbol) && !isAnonymous(symbol)) { - return new LightClassUsage(id(symbol, byteArrayEnumerator)); - } - } - else { - Symbol owner = symbol.owner; - if (isPrivate(symbol)) { - return null; - } - if (symbol instanceof Symbol.VarSymbol) { - return new LightFieldUsage(id(owner, byteArrayEnumerator), id(symbol, byteArrayEnumerator)); - } - else if (symbol instanceof Symbol.MethodSymbol) { - int paramCount = ((Symbol.MethodSymbol)symbol).type.getParameterTypes().size(); - return new LightMethodUsage(id(owner, byteArrayEnumerator), id(symbol, byteArrayEnumerator), paramCount); - } - else { - throw new AssertionError("unexpected symbol: " + symbol + " class: " + symbol.getClass() + " kind: " + kind); - } - } - return null; - } - - // JDK-6 has no Symbol.isPrivate() method - private static boolean isPrivate(Symbol symbol) { - return (symbol.flags() & Flags.AccessFlags) == PRIVATE; - } - - // JDK-6 has no Symbol.isAnonymous() method - private static boolean isAnonymous(Symbol symbol) { - return symbol.name.isEmpty(); - } - - private static int id(Symbol symbol, ByteArrayEnumerator byteArrayEnumerator) { - return byteArrayEnumerator.enumerate(bytes(symbol)); - } -} diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/JavacReferencesCollector.java b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/JavacReferencesCollector.java index 6a597ba4fc44..f461708dfe21 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/JavacReferencesCollector.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/JavacReferencesCollector.java @@ -32,10 +32,11 @@ import org.jetbrains.jps.service.JpsServiceManager; import javax.lang.model.element.ElementKind; import javax.lang.model.element.TypeElement; -import javax.tools.*; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; public class JavacReferencesCollector { public static void installOn(JavacTask task) { @@ -76,12 +77,12 @@ public class JavacReferencesCollector { private final JavacFileReferencesRegistrar[] myOnlyImportsListeners; private final JavacTreeRefScanner myAstScanner; - private Name myAsteriks; + private Name myAsterisk; - private int myRemainDecls; + private int myRemainDeclarations; private JCTree.JCCompilationUnit myCurrentCompilationUnit; private Set myCollectedReferences; - private Set myCollectedDefinitions; + private List myCollectedDefinitions; public MyTaskListener(JavacFileReferencesRegistrar[] fullASTListenerArray, JavacFileReferencesRegistrar[] importsListenerArray) { myFullASTListeners = fullASTListenerArray; @@ -101,16 +102,16 @@ public class JavacReferencesCollector { // javac creates an event on each processed top level declared class not file if (myCurrentCompilationUnit != e.getCompilationUnit()) { myCurrentCompilationUnit = (JCTree.JCCompilationUnit)e.getCompilationUnit(); - myCollectedDefinitions = new THashSet(); + myCollectedDefinitions = new ArrayList(); myCollectedReferences = new THashSet(); - myRemainDecls = myCurrentCompilationUnit.getTypeDecls().size() - 1; + myRemainDeclarations = myCurrentCompilationUnit.getTypeDecls().size() - 1; scanImports(myCurrentCompilationUnit, myCollectedReferences); for(JavacFileReferencesRegistrar r: myOnlyImportsListeners) { r.registerFile(e.getSourceFile(), myCollectedReferences, myCollectedDefinitions); } } else { - myRemainDecls--; + myRemainDeclarations--; } JavacTreeScannerSink sink = new JavacTreeScannerSink() { @@ -134,7 +135,7 @@ public class JavacReferencesCollector { } } - if (myRemainDecls == 0) { + if (myRemainDeclarations == 0) { if (myFullASTListeners.length != 0) { for (JCTree.JCAnnotation annotation : myCurrentCompilationUnit.getPackageAnnotations()) { myAstScanner.scan(annotation, sink); @@ -158,10 +159,10 @@ public class JavacReferencesCollector { } private Name getAsteriskFromCurrentNameTable(Name tableRepresentative) { - if (myAsteriks == null) { - myAsteriks = tableRepresentative.table.fromChars(new char[]{'*'}, 0, 1); + if (myAsterisk == null) { + myAsterisk = tableRepresentative.table.fromChars(new char[]{'*'}, 0, 1); } - return myAsteriks; + return myAsterisk; } private void scanImports(JCTree.JCCompilationUnit compilationUnit, Set symbols) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/api/JavacFileReferencesRegistrar.java b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/api/JavacFileReferencesRegistrar.java index 8498ba7057c6..b03f0e1e813e 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/api/JavacFileReferencesRegistrar.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/api/JavacFileReferencesRegistrar.java @@ -16,7 +16,7 @@ package org.jetbrains.jps.javac.ast.api; import javax.tools.*; -import java.util.Collection; +import java.util.List; import java.util.Set; public interface JavacFileReferencesRegistrar { @@ -25,5 +25,5 @@ public interface JavacFileReferencesRegistrar { boolean onlyImports(); - void registerFile(JavaFileObject file, Set refs, Collection defs); + void registerFile(JavaFileObject file, Set refs, List defs); } diff --git a/jps/jps-builders/testSrc/org/jetbrains/references/ReferenceIndexTestBase.kt b/jps/jps-builders/testSrc/org/jetbrains/references/ReferenceIndexTestBase.kt index 3d96dd828fc2..accc05100e94 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/references/ReferenceIndexTestBase.kt +++ b/jps/jps-builders/testSrc/org/jetbrains/references/ReferenceIndexTestBase.kt @@ -17,14 +17,13 @@ package org.jetbrains.references import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.vfs.CharsetToolkit -import com.intellij.openapi.vfs.VfsUtil import com.intellij.util.PathUtil import com.intellij.util.io.PersistentStringEnumerator import com.sun.tools.javac.util.Convert import org.jetbrains.jps.backwardRefs.BackwardReferenceIndexWriter import org.jetbrains.jps.backwardRefs.ByteArrayEnumerator import org.jetbrains.jps.backwardRefs.CompilerBackwardReferenceIndex -import org.jetbrains.jps.backwardRefs.LightUsage +import org.jetbrains.jps.backwardRefs.LightRef import org.jetbrains.jps.builders.JpsBuildTestCase import org.jetbrains.jps.builders.TestProjectBuilderLogger import org.jetbrains.jps.builders.logging.BuildLoggingManager @@ -135,15 +134,14 @@ abstract class ReferenceIndexTestBase : JpsBuildTestCase() { private fun Int.asName(byteArrayEnumerator: ByteArrayEnumerator): String = Convert.utf2string(byteArrayEnumerator.valueOf(this)) - private fun CompilerBackwardReferenceIndex.LightDefinition.asText(byteArrayEnumerator: ByteArrayEnumerator) = this.usage.asText(byteArrayEnumerator) + private fun CompilerBackwardReferenceIndex.LightDefinition.asText(byteArrayEnumerator: ByteArrayEnumerator) = this.ref.asText(byteArrayEnumerator) - private fun LightUsage.asText(byteArrayEnumerator: ByteArrayEnumerator): String = + private fun LightRef.asText(byteArrayEnumerator: ByteArrayEnumerator): String = when (this) { - is LightUsage.LightMethodUsage -> this.owner.name.asName(byteArrayEnumerator) + "." + this.name.asName( - byteArrayEnumerator) + "(" + this.parameterCount + ")" - is LightUsage.LightFieldUsage -> this.owner.name.asName(byteArrayEnumerator) + "." + this.name.asName(byteArrayEnumerator) - is LightUsage.LightClassUsage -> this.name.asName(byteArrayEnumerator) - is LightUsage.LightFunExprUsage -> "fun_expr(" + this.name.asName(byteArrayEnumerator) + ")" + is LightRef.JavaLightMethodRef -> "${this.owner.name.asName(byteArrayEnumerator)}.${this.name.asName(byteArrayEnumerator)}(${this.parameterCount})" + is LightRef.JavaLightFieldRef -> "${this.owner.name.asName(byteArrayEnumerator)}.${this.name.asName(byteArrayEnumerator)}" + is LightRef.JavaLightClassRef -> this.name.asName(byteArrayEnumerator) + is LightRef.JavaLightFunExprDef -> "fun_expr(id=${this.id})" else -> throw UnsupportedOperationException() }