mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-13 21:55:01 +07:00
javac ast refs index
This commit is contained in:
@@ -208,6 +208,7 @@ def layoutFull(BuildContext context) {
|
||||
module("forms_rt")
|
||||
module("instrumentation-util")
|
||||
module("instrumentation-util-8")
|
||||
module("javac-ref-scanner-8")
|
||||
}
|
||||
|
||||
jar("jps-model.jar") {
|
||||
@@ -886,6 +887,7 @@ def layoutJps(String home, String targetDir, String buildNumber, Closure additio
|
||||
module("forms-compiler")
|
||||
module("instrumentation-util")
|
||||
module("instrumentation-util-8")
|
||||
module("javac-ref-scanner-8")
|
||||
module("jps-builders")
|
||||
module("jps-standalone-builder")
|
||||
module("java-runtime")
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.fileTypes.FileType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.backwardRefs.CompilerElement;
|
||||
|
||||
public interface CompilerReferenceConverter {
|
||||
@NotNull
|
||||
FileType getAvailabilitySrcFileType();
|
||||
|
||||
@Nullable
|
||||
CompilerElement sourceElementAsCompilerElement(@NotNull PsiElement element);
|
||||
|
||||
@NotNull
|
||||
CompilerElement[] libraryElementAsCompilerElements(@NotNull PsiElement element);
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.compiler.server.BuildProcessParametersProvider;
|
||||
import com.intellij.find.bytecode.CompilerReferenceService;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.backwardRefs.BackwardReferenceIndexWriter;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class CompilerReferenceIndexBuildParametersProvider extends BuildProcessParametersProvider {
|
||||
@NotNull
|
||||
@Override
|
||||
public List<String> getVMArguments() {
|
||||
return CompilerReferenceService.isEnabled()
|
||||
? Collections.singletonList("-D" + BackwardReferenceIndexWriter.PROP_KEY + "=true")
|
||||
: Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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.compiler.server.BuildManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileWithId;
|
||||
import com.intellij.util.containers.Queue;
|
||||
import gnu.trove.TIntHashSet;
|
||||
import gnu.trove.TIntProcedure;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.backwardRefs.CompilerElement;
|
||||
import org.jetbrains.jps.backwardRefs.CompilerBackwardReferenceIndex;
|
||||
import org.jetbrains.jps.backwardRefs.LightUsage;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
|
||||
public class CompilerReferenceReader {
|
||||
private final CompilerBackwardReferenceIndex myIndex;
|
||||
|
||||
private CompilerReferenceReader(File buildDir) throws IOException {
|
||||
myIndex = new CompilerBackwardReferenceIndex(buildDir);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public TIntHashSet findReferentFileIds(@NotNull CompilerElement element) {
|
||||
LightUsage usage = element.asUsage(myIndex.getByteSeqEum());
|
||||
|
||||
TIntHashSet set = new TIntHashSet();
|
||||
for (int classId : getWholeHierarchy(usage.getOwner())) {
|
||||
final LightUsage overriderUsage = usage.override(classId);
|
||||
final Collection<Integer> usageFiles = myIndex.getBackwardReferenceMap().get(overriderUsage);
|
||||
if (usageFiles != null) {
|
||||
for (int fileId : usageFiles) {
|
||||
final VirtualFile file = findFile(fileId);
|
||||
if (file != null) {
|
||||
set.add(((VirtualFileWithId)file).getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
myIndex.close();
|
||||
}
|
||||
|
||||
public static CompilerReferenceReader create(Project project) {
|
||||
File buildDir = BuildManager.getInstance().getProjectSystemDirectory(project);
|
||||
if (buildDir == null || CompilerBackwardReferenceIndex.versionDiffers(buildDir)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return new CompilerReferenceReader(buildDir);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private VirtualFile findFile(int id) {
|
||||
try {
|
||||
String path = myIndex.getFilePathEnumerator().valueOf(id);
|
||||
assert path != null;
|
||||
return VfsUtil.findFileByIoFile(new File(path), false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private int[] getWholeHierarchy(int classId) {
|
||||
TIntHashSet result = new TIntHashSet();
|
||||
Queue<Integer> q = new Queue<>(10);
|
||||
q.addLast(classId);
|
||||
while (!q.isEmpty()) {
|
||||
int curId = q.pullFirst();
|
||||
if (result.add(curId)) {
|
||||
final TIntHashSet subclasses = myIndex.getBackwardHierarchyMap().get(curId);
|
||||
if (subclasses != null) {
|
||||
subclasses.forEach(new TIntProcedure() {
|
||||
@Override
|
||||
public boolean execute(int nextId) {
|
||||
q.addLast(nextId);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.toArray();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
* 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.find.bytecode.CompilerReferenceService;
|
||||
import com.intellij.openapi.compiler.CompileContext;
|
||||
import com.intellij.openapi.compiler.CompileTask;
|
||||
import com.intellij.openapi.compiler.CompilerManager;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ModuleRootManager;
|
||||
import com.intellij.openapi.roots.ProjectFileIndex;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.vfs.*;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.ProjectScope;
|
||||
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 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.CompilerElement;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class CompilerReferenceServiceImpl extends CompilerReferenceService {
|
||||
private static final CompilerReferenceConverter[] BYTECODE_CONVERTERS =
|
||||
new CompilerReferenceConverter[]{new JavaCompilerReferenceConverter()};
|
||||
|
||||
private final ProjectFileIndex myProjectFileIndex;
|
||||
private final Set<Module> myChangedModules = ContainerUtil.newConcurrentSet();
|
||||
private final Set<FileType> myFileTypes;
|
||||
|
||||
private volatile CompilerReferenceReader myReader;
|
||||
|
||||
private final Object myLock = new Object();
|
||||
|
||||
public CompilerReferenceServiceImpl(Project project) {
|
||||
super(project);
|
||||
myProjectFileIndex = ProjectRootManager.getInstance(project).getFileIndex();
|
||||
myFileTypes = Collections.unmodifiableSet(
|
||||
Stream.of(BYTECODE_CONVERTERS).map(CompilerReferenceConverter::getAvailabilitySrcFileType).collect(Collectors.toSet()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void projectOpened() {
|
||||
if (isEnabled()) {
|
||||
CompilerManager.getInstance(myProject).addBeforeTask(new CompileTask() {
|
||||
@Override
|
||||
public boolean execute(CompileContext context) {
|
||||
closeReaderIfNeed();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
CompilerManager.getInstance(myProject).addAfterTask(new CompileTask() {
|
||||
@Override
|
||||
public boolean execute(CompileContext context) {
|
||||
myChangedModules.clear();
|
||||
openReaderIfNeed();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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) {
|
||||
if (myReader != null && myProjectFileIndex.isInSourceContent(file) && myFileTypes.contains(file.getFileType())) {
|
||||
final Module module = myProjectFileIndex.getModuleForFile(file);
|
||||
if (module != null) {
|
||||
myChangedModules.add(module);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, myProject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void projectClosed() {
|
||||
closeReaderIfNeed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GlobalSearchScope getScopeWithoutReferences(@NotNull PsiElement element) {
|
||||
if (!isServiceEnabled()) return null;
|
||||
return CachedValuesManager.getCachedValue(element, () -> CachedValueProvider.Result.create(calculateScopeWithoutReferences(element),
|
||||
PsiModificationTracker.MODIFICATION_COUNT));
|
||||
}
|
||||
|
||||
private boolean isServiceEnabled() {
|
||||
return myReader != null && isEnabled();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private GlobalSearchScope calculateScopeWithoutReferences(@NotNull PsiElement element) {
|
||||
TIntHashSet referentFileIds = getReferentFileIds(element);
|
||||
if (referentFileIds == null) return null;
|
||||
|
||||
final GlobalSearchScope everythingIsClearScope = GlobalSearchScope
|
||||
.getScopeRestrictedByFileTypes(ProjectScope.getContentScope(myProject), myFileTypes.toArray(new FileType[myFileTypes.size()]));
|
||||
return new ScopeWithoutBytecodeReferences(referentFileIds).intersectWith(everythingIsClearScope);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private TIntHashSet getReferentFileIds(@NotNull PsiElement element) {
|
||||
final PsiFile file = element.getContainingFile();
|
||||
if (file == null) return null;
|
||||
final VirtualFile vFile = file.getVirtualFile();
|
||||
if (vFile == null) return null;
|
||||
|
||||
ElementPlace place = ElementPlace.get(vFile, myProjectFileIndex);
|
||||
if (place == null) {
|
||||
return null;
|
||||
}
|
||||
if (!myChangedModules.isEmpty()) {
|
||||
final Module module = myProjectFileIndex.getModuleForFile(vFile);
|
||||
if (module == null || areDependenciesOrSelfChanged(module, new THashSet<>())) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
final FileType type = vFile.getFileType();
|
||||
CompilerElement[] compilerElements = null;
|
||||
if (place == ElementPlace.SRC) {
|
||||
for (CompilerReferenceConverter converter : BYTECODE_CONVERTERS) {
|
||||
if (converter.getAvailabilitySrcFileType().equals(type)) {
|
||||
final CompilerElement compilerElement = converter.sourceElementAsCompilerElement(element);
|
||||
compilerElements = compilerElement == null ? CompilerElement.EMPTY_ARRAY : new CompilerElement[]{compilerElement};
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (CompilerReferenceConverter converter : BYTECODE_CONVERTERS) {
|
||||
compilerElements = converter.libraryElementAsCompilerElements(element);
|
||||
if (compilerElements.length != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (compilerElements == null || compilerElements.length == 0) return null;
|
||||
|
||||
synchronized (myLock) {
|
||||
if (myReader == null) return null;
|
||||
TIntHashSet referentFileIds = new TIntHashSet();
|
||||
for (CompilerElement compilerElement : compilerElements) {
|
||||
referentFileIds.addAll(myReader.findReferentFileIds(compilerElement).toArray());
|
||||
}
|
||||
return referentFileIds;
|
||||
}
|
||||
}
|
||||
|
||||
private void closeReaderIfNeed() {
|
||||
synchronized (myLock) {
|
||||
if (myReader != null) {
|
||||
myReader.close();
|
||||
myReader = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void openReaderIfNeed() {
|
||||
synchronized (myLock) {
|
||||
if (myProject.isOpen()) {
|
||||
myReader = CompilerReferenceReader.create(myProject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
@Nullable
|
||||
public Set<VirtualFile> getReferentFiles(@NotNull PsiElement element) {
|
||||
FileBasedIndex fileIndex = FileBasedIndex.getInstance();
|
||||
final TIntHashSet ids = getReferentFileIds(element);
|
||||
if (ids == null) return null;
|
||||
Set<VirtualFile> fileSet = new THashSet<>();
|
||||
ids.forEach(id -> {
|
||||
final VirtualFile vFile = fileIndex.findFileById(myProject, id);
|
||||
assert vFile != null;
|
||||
fileSet.add(vFile);
|
||||
return true;
|
||||
});
|
||||
return fileSet;
|
||||
}
|
||||
|
||||
private enum ElementPlace {
|
||||
SRC, LIB;
|
||||
|
||||
private static ElementPlace get(VirtualFile file, ProjectFileIndex index) {
|
||||
return index.isInSourceContent(file) ? SRC :
|
||||
((index.isInLibrarySource(file) || index.isInLibraryClasses(file)) ? LIB : null);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ScopeWithoutBytecodeReferences extends GlobalSearchScope {
|
||||
private final TIntHashSet myReferentIds;
|
||||
|
||||
private ScopeWithoutBytecodeReferences(TIntHashSet ids) {
|
||||
myReferentIds = ids;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(@NotNull VirtualFile file) {
|
||||
return !(file instanceof VirtualFileWithId) || !myReferentIds.contains(((VirtualFileWithId)file).getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(@NotNull VirtualFile file1, @NotNull VirtualFile file2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSearchInModuleContent(@NotNull Module aModule) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSearchInLibraries() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean areDependenciesOrSelfChanged(Module module, THashSet<Module> uniqueModules) {
|
||||
if (!uniqueModules.add(module)) {
|
||||
return false;
|
||||
}
|
||||
if (myChangedModules.contains(module)) {
|
||||
return true;
|
||||
}
|
||||
for (Module dependency : ModuleRootManager.getInstance(module).getDependencies()) {
|
||||
if (areDependenciesOrSelfChanged(dependency, uniqueModules)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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.fileTypes.FileType;
|
||||
import com.intellij.openapi.fileTypes.StdFileTypes;
|
||||
import com.intellij.openapi.roots.impl.LibraryScopeCache;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.searches.ClassInheritorsSearch;
|
||||
import com.intellij.psi.util.ClassUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.Processor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.backwardRefs.CompilerElement;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class JavaCompilerReferenceConverter implements CompilerReferenceConverter {
|
||||
@NotNull
|
||||
@Override
|
||||
public FileType getAvailabilitySrcFileType() {
|
||||
return StdFileTypes.JAVA;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public CompilerElement sourceElementAsCompilerElement(@NotNull PsiElement element) {
|
||||
if (mayBeVisibleOutsideOwnerFile(element)) {
|
||||
if (element instanceof PsiField) {
|
||||
final PsiField field = (PsiField)element;
|
||||
final PsiClass aClass = field.getContainingClass();
|
||||
if (PsiUtil.isCompileTimeConstant((PsiVariable)field)) {
|
||||
return null;
|
||||
}
|
||||
if (aClass == null || aClass instanceof PsiAnonymousClass) return null;
|
||||
final String jvmOwnerName = aClass.getQualifiedName();
|
||||
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 = aClass.getQualifiedName();
|
||||
if (jvmOwnerName == null) return null;
|
||||
final PsiMethod method = (PsiMethod)element;
|
||||
final String name = method.isConstructor() ? "<init>" : 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public CompilerElement[] libraryElementAsCompilerElements(@NotNull PsiElement element) {
|
||||
if (mayBeVisibleOutsideOwnerFile(element)) {
|
||||
if (element instanceof PsiField || element instanceof PsiMethod) {
|
||||
final String name = ((PsiMember)element).getName();
|
||||
|
||||
final Function<String, CompilerElement> builder;
|
||||
if (element instanceof PsiField) {
|
||||
builder = (ownerJvmName) -> new CompilerElement.CompilerField(ownerJvmName, name);
|
||||
}
|
||||
else {
|
||||
final int parametersCount = ((PsiMethod)element).getParameterList().getParametersCount();
|
||||
builder = (ownerJvmName) -> new CompilerElement.CompilerMethod(ownerJvmName, name, parametersCount);
|
||||
}
|
||||
|
||||
final List<CompilerElement> result = new ArrayList<>();
|
||||
inLibrariesHierarchy(((PsiMember)element).getContainingClass(), aClass -> {
|
||||
final String jvmClassName = aClass.getQualifiedName();
|
||||
if (jvmClassName != null) {
|
||||
result.add(builder.apply(jvmClassName));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return result.toArray(new CompilerElement[result.size()]);
|
||||
}
|
||||
else if (element instanceof PsiClass) {
|
||||
final List<CompilerElement> result = new ArrayList<>();
|
||||
inLibrariesHierarchy((PsiClass)element, aClass -> {
|
||||
final String jvmClassName = aClass.getQualifiedName();
|
||||
if (jvmClassName != null) {
|
||||
result.add(new CompilerElement.CompilerClass(jvmClassName));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return result.toArray(new CompilerElement[result.size()]);
|
||||
}
|
||||
}
|
||||
return CompilerElement.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 void inLibrariesHierarchy(PsiClass aClass, Processor<PsiClass> processor) {
|
||||
if (aClass != null) {
|
||||
processor.process(aClass);
|
||||
ClassInheritorsSearch.search(aClass, LibraryScopeCache.getInstance(aClass.getProject()).getLibrariesOnlyScope(), true)
|
||||
.forEach(processor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
public class Foo {
|
||||
|
||||
public void b<caret>ar() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
public class Bar {
|
||||
|
||||
public String getMyName() {
|
||||
return "Bar...";
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
public class Baz {
|
||||
public void main(FooImpl f) {
|
||||
System.out.println(f.getMyName());
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
public interface Foo {
|
||||
|
||||
String getM<caret>yName();
|
||||
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
public class FooImpl implements Foo {
|
||||
|
||||
public String getMyName() {
|
||||
return "FooImpl is my name";
|
||||
};
|
||||
|
||||
}
|
||||
+4
@@ -56,6 +56,10 @@ public abstract class AbstractCompilerAwareTest extends JavaCodeInsightFixtureTe
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
rebuildProject();
|
||||
}
|
||||
|
||||
protected void rebuildProject() {
|
||||
for (final CompilerMessage compilerMessage : myCompilerTester.rebuild()) {
|
||||
assertNotSame(compilerMessage.getMessage(), CompilerMessageCategory.ERROR, compilerMessage.getCategory());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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.JavaTestUtil;
|
||||
import com.intellij.codeInsight.completion.AbstractCompilerAwareTest;
|
||||
import com.intellij.find.bytecode.CompilerReferenceService;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiMember;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.testFramework.SkipSlowTestLocally;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@SkipSlowTestLocally
|
||||
public class CompilerReferencesTest extends AbstractCompilerAwareTest {
|
||||
private boolean myDefaultEnableState;
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
myDefaultEnableState = CompilerReferenceService.IS_ENABLED_KEY.asBoolean();
|
||||
CompilerReferenceService.IS_ENABLED_KEY.setValue(true);
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tearDown() throws Exception {
|
||||
CompilerReferenceService.IS_ENABLED_KEY.setValue(myDefaultEnableState);
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
protected String getTestDataPath() {
|
||||
return JavaTestUtil.getJavaTestDataPath() + "/compiler/bytecodeReferences/";
|
||||
}
|
||||
|
||||
public void testIsNotReady() {
|
||||
myFixture.configureByFile(getName() + "/Foo.java");
|
||||
assertNull(getReferentFilesForElementUnderCaret());
|
||||
}
|
||||
|
||||
public void testSimpleUsagesInFullyCompiledProject() {
|
||||
myFixture.configureByFiles(getName() + "/Foo.java", getName() + "/Bar.java", getName() + "/Baz.java", getName() + "/FooImpl.java");
|
||||
rebuildProject();
|
||||
|
||||
final Set<VirtualFile> referents = getReferentFilesForElementUnderCaret();
|
||||
assertNotNull(referents);
|
||||
final Set<String> 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());
|
||||
}
|
||||
|
||||
private Set<VirtualFile> 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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module" module-name="jps-builders" />
|
||||
<orderEntry type="library" scope="TEST" name="KotlinJavaRuntime" level="project" />
|
||||
<orderEntry type="module" module-name="core-api" scope="TEST" />
|
||||
<orderEntry type="module" module-name="testFramework" scope="TEST" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -0,0 +1,33 @@
|
||||
package org.jetbrains.jps.javac.ast;
|
||||
|
||||
import com.sun.source.tree.LambdaExpressionTree;
|
||||
import com.sun.source.tree.MemberReferenceTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import com.sun.tools.javac.code.Symbol;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import org.jetbrains.jps.javac.ast.api.JavacRefSymbol;
|
||||
|
||||
/**
|
||||
* Used via reflection in {@link JavacTreeRefScanner#createASTScanner()}
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class Javac8RefScanner extends JavacTreeRefScanner {
|
||||
@Override
|
||||
public Tree visitLambdaExpression(LambdaExpressionTree node, JavacTreeScannerSink sink) {
|
||||
final Type type = ((JCTree.JCLambda)node).type;
|
||||
final Symbol.TypeSymbol symbol = type.asElement();
|
||||
sink.sinkReference(new JavacRefSymbol(symbol, Tree.Kind.LAMBDA_EXPRESSION));
|
||||
//for (Symbol member : symbol.members().getElements()) {
|
||||
// sink.mySymbols.add(new JavacRefSymbol(member, Tree.Kind.LAMBDA_EXPRESSION));
|
||||
//}
|
||||
return super.visitLambdaExpression(node, sink);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tree visitMemberReference(MemberReferenceTree node, JavacTreeScannerSink sink) {
|
||||
final Symbol methodSymbol = ((JCTree.JCMemberReference)node).sym;
|
||||
sink.sinkReference(new JavacRefSymbol(methodSymbol, Tree.Kind.MEMBER_REFERENCE));
|
||||
return super.visitMemberReference(node, sink);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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.references
|
||||
|
||||
import com.intellij.openapi.application.ex.PathManagerEx
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
|
||||
class Java8ReferenceIndexTest : ReferenceIndexTestBase() {
|
||||
fun testLambda() {
|
||||
assertIndexOnRebuild("Lambda.java")
|
||||
}
|
||||
|
||||
fun testMethodReference() {
|
||||
assertIndexOnRebuild("MethodReference.java")
|
||||
}
|
||||
|
||||
override fun getTestDataRootPath(): String {
|
||||
return FileUtil.toCanonicalPath(PathManagerEx.findFileUnderCommunityHome("jps/javac-ref-scanner-8/testData/referenceIndex").absolutePath, '/')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
public class Lambda {
|
||||
public static void main(String[] args) {
|
||||
new Thread(() -> {
|
||||
|
||||
//Do nothing
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
Backward Hierarchy:
|
||||
java.lang.Object -> Lambda
|
||||
|
||||
Backward References:
|
||||
Lambda in Lambda
|
||||
Lambda.<init>(0) in Lambda
|
||||
Lambda.main(1) in Lambda
|
||||
java.lang.Object.<init>(0) in Lambda
|
||||
java.lang.Runnable in Lambda
|
||||
java.lang.String in Lambda
|
||||
java.lang.Thread in Lambda
|
||||
@@ -0,0 +1,7 @@
|
||||
import java.util.Collections;
|
||||
|
||||
public class MethodReference {
|
||||
public static void main(String[] args) {
|
||||
new Thread(Collections::emptyList);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
Backward Hierarchy:
|
||||
java.lang.Object -> MethodReference
|
||||
|
||||
Backward References:
|
||||
MethodReference in MethodReference
|
||||
MethodReference.<init>(0) in MethodReference
|
||||
MethodReference.main(1) in MethodReference
|
||||
java.lang.Object.<init>(0) in MethodReference
|
||||
java.lang.String in MethodReference
|
||||
java.lang.Thread in MethodReference
|
||||
java.util.Collections in MethodReference
|
||||
java.util.Collections.emptyList(0) in MethodReference
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
org.jetbrains.jps.backwardRefs.BackwardReferenceRegistrar
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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 org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.ModuleChunk;
|
||||
import org.jetbrains.jps.builders.DirtyFilesHolder;
|
||||
import org.jetbrains.jps.builders.java.JavaSourceRootDescriptor;
|
||||
import org.jetbrains.jps.incremental.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class BackwardReferenceIndexBuilder extends ModuleLevelBuilder {
|
||||
public BackwardReferenceIndexBuilder() {
|
||||
super(BuilderCategory.INITIAL);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getPresentableName() {
|
||||
return "backward-references indexer";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildStarted(CompileContext context) {
|
||||
BackwardReferenceIndexWriter.initialize(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildFinished(CompileContext context) {
|
||||
final BackwardReferenceIndexWriter writer = BackwardReferenceIndexWriter.getInstance();
|
||||
if (writer != null) {
|
||||
writer.closeIfNeed();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExitCode build(CompileContext context,
|
||||
ModuleChunk chunk,
|
||||
DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget> dirtyFilesHolder,
|
||||
OutputConsumer outputConsumer) throws ProjectBuildException, IOException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+183
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* 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.SystemProperties;
|
||||
import com.sun.tools.javac.code.Symbol;
|
||||
import gnu.trove.TIntHashSet;
|
||||
import gnu.trove.TIntProcedure;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.builders.java.JavaBuilderUtil;
|
||||
import org.jetbrains.jps.builders.storage.BuildDataCorruptedException;
|
||||
import org.jetbrains.jps.incremental.CompileContext;
|
||||
import org.jetbrains.jps.incremental.java.JavaBuilder;
|
||||
import org.jetbrains.jps.incremental.storage.BuildDataManager;
|
||||
import org.jetbrains.jps.javac.ast.api.JavacRefSymbol;
|
||||
import org.jetbrains.jps.model.java.compiler.JavaCompilers;
|
||||
|
||||
import javax.tools.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
public class BackwardReferenceIndexWriter {
|
||||
public static final String PROP_KEY = "ref.index.builder";
|
||||
|
||||
private static volatile BackwardReferenceIndexWriter ourInstance;
|
||||
|
||||
private final CompilerBackwardReferenceIndex myIndex;
|
||||
private final boolean myRebuild;
|
||||
|
||||
private BackwardReferenceIndexWriter(CompilerBackwardReferenceIndex index, boolean rebuild) {
|
||||
myIndex = index;
|
||||
myRebuild = rebuild;
|
||||
}
|
||||
|
||||
static BackwardReferenceIndexWriter getInstance() {
|
||||
return ourInstance;
|
||||
}
|
||||
|
||||
static void initialize(@NotNull CompileContext context) {
|
||||
if (isEnabled()) {
|
||||
final BuildDataManager dataManager = context.getProjectDescriptor().dataManager;
|
||||
final File buildDir = dataManager.getDataPaths().getDataStorageRoot();
|
||||
boolean isRebuild = JavaBuilderUtil.isForcedRecompilationAllJavaModules(context);
|
||||
|
||||
if (!JavaCompilers.JAVAC_ID.equals(JavaBuilder.getUsedCompilerId(context))) {
|
||||
CompilerBackwardReferenceIndex.removeIndexFiles(buildDir);
|
||||
return;
|
||||
}
|
||||
if (isRebuild) {
|
||||
CompilerBackwardReferenceIndex.removeIndexFiles(buildDir);
|
||||
}
|
||||
else if (CompilerBackwardReferenceIndex.versionDiffers(buildDir)) {
|
||||
throw new BuildDataCorruptedException(new IOException("backward reference index should be updated to actual version"));
|
||||
}
|
||||
|
||||
if (CompilerBackwardReferenceIndex.exist(buildDir) || isRebuild) {
|
||||
ourInstance = new BackwardReferenceIndexWriter(new CompilerBackwardReferenceIndex(buildDir), isRebuild);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static boolean isEnabled() {
|
||||
return SystemProperties.getBooleanProperty(PROP_KEY, false);
|
||||
}
|
||||
|
||||
void closeIfNeed() {
|
||||
myIndex.close();
|
||||
}
|
||||
|
||||
synchronized void writeReferences(JavaFileObject file, Set<JavacRefSymbol> refs) {
|
||||
final LightUsage[] usages = new LightUsage[refs.size()];
|
||||
int idx = 0;
|
||||
final ByteArrayEnumerator byteSeqEum = myIndex.getByteSeqEum();
|
||||
for (JavacRefSymbol ref : refs) {
|
||||
usages[idx++] = LightUsage.fromSymbol(ref.getSymbol(), byteSeqEum);
|
||||
}
|
||||
|
||||
final int fileId = enumerateFile(file);
|
||||
if (myRebuild) {
|
||||
for (LightUsage usage : usages) {
|
||||
myIndex.getBackwardReferenceMap().put(usage, fileId);
|
||||
myIndex.getReferenceMap().put(fileId, usage);
|
||||
}
|
||||
}
|
||||
else {
|
||||
updateReferenceIndicesIncrementally(fileId, usages);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateReferenceIndicesIncrementally(int fileId, LightUsage[] usages) {
|
||||
final Collection<LightUsage> rawOldUsages = myIndex.getReferenceMap().get(fileId);
|
||||
Collection<LightUsage> oldUsages = rawOldUsages == null ? null : new ArrayList<LightUsage>(rawOldUsages);
|
||||
for (LightUsage usage : usages) {
|
||||
if (oldUsages == null || !oldUsages.remove(usage)) {
|
||||
myIndex.getBackwardReferenceMap().put(usage, fileId);
|
||||
myIndex.getReferenceMap().put(fileId, usage);
|
||||
}
|
||||
}
|
||||
if (oldUsages != null && !oldUsages.isEmpty()) {
|
||||
myIndex.getReferenceMap().removeAll(fileId, oldUsages);
|
||||
for (LightUsage usage : oldUsages) {
|
||||
myIndex.getBackwardReferenceMap().removeFrom(usage, fileId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
synchronized void writeHierarchy(Symbol name, Symbol[] supers) {
|
||||
if (supers.length == 0) {
|
||||
return;
|
||||
}
|
||||
final int classId = classId(name);
|
||||
final int[] superIds = new int[supers.length];
|
||||
for (int i = 0; i < supers.length; i++) {
|
||||
superIds[i] = classId(supers[i]);
|
||||
}
|
||||
|
||||
if (myRebuild) {
|
||||
directlyWriteHierarchyIndices(classId, superIds);
|
||||
}
|
||||
else {
|
||||
updateHierarchyIndicesIncrementally(classId, superIds);
|
||||
}
|
||||
}
|
||||
|
||||
private void directlyWriteHierarchyIndices(int classId, int[] superIds) {
|
||||
for (int superId : superIds) {
|
||||
myIndex.getBackwardHierarchyMap().put(superId, classId);
|
||||
myIndex.getHierarchyMap().put(classId, superId);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateHierarchyIndicesIncrementally(final int classId, int[] superIds) {
|
||||
final TIntHashSet rawOldSupers = myIndex.getHierarchyMap().get(classId);
|
||||
TIntHashSet oldSuperClasses = rawOldSupers == null ? null : new TIntHashSet(rawOldSupers);
|
||||
for (int superId: superIds) {
|
||||
if (oldSuperClasses == null || !oldSuperClasses.remove(superId)) {
|
||||
myIndex.getBackwardHierarchyMap().put(superId, classId);
|
||||
myIndex.getHierarchyMap().put(classId, superId);
|
||||
}
|
||||
}
|
||||
if (oldSuperClasses != null && !oldSuperClasses.isEmpty()) {
|
||||
myIndex.getHierarchyMap().removeAll(classId, oldSuperClasses);
|
||||
oldSuperClasses.forEach(new TIntProcedure() {
|
||||
@Override
|
||||
public boolean execute(int oldSuperId) {
|
||||
myIndex.getBackwardHierarchyMap().put(oldSuperId, classId);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private int classId(Symbol name) {
|
||||
return myIndex.getByteSeqEum().enumerate(LightUsage.bytes(name));
|
||||
}
|
||||
|
||||
private int enumerateFile(JavaFileObject file) {
|
||||
try {
|
||||
return myIndex.getFilePathEnumerator().enumerate(file.getName());
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new BuildDataCorruptedException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.sun.tools.javac.code.Symbol;
|
||||
import org.jetbrains.jps.javac.ast.api.JavacFileReferencesRegistrar;
|
||||
import org.jetbrains.jps.javac.ast.api.JavacRefSymbol;
|
||||
|
||||
import javax.tools.*;
|
||||
import java.util.Set;
|
||||
|
||||
public class BackwardReferenceRegistrar implements JavacFileReferencesRegistrar {
|
||||
private BackwardReferenceIndexWriter myWriter;
|
||||
|
||||
@Override
|
||||
public boolean initialize() {
|
||||
myWriter = BackwardReferenceIndexWriter.getInstance();
|
||||
return myWriter != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onlyImports() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerReferences(JavaFileObject file, Set<JavacRefSymbol> refs) {
|
||||
myWriter.writeReferences(file, refs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerClassDeclaration(Symbol className, Symbol[] supers) {
|
||||
myWriter.writeHierarchy(className, supers);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.builders.storage.BuildDataCorruptedException;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class ByteArrayEnumerator extends PersistentEnumeratorDelegate<byte[]> {
|
||||
@Nullable private final CachingEnumerator<byte[]> myCache;
|
||||
|
||||
public ByteArrayEnumerator(@NotNull final File file) throws IOException {
|
||||
super(file, ByteSequenceDataExternalizer.INSTANCE, 1024 * 4, null);
|
||||
myCache = new CachingEnumerator<byte[]>(new DataEnumerator<byte[]>() {
|
||||
@Override
|
||||
public int enumerate(@Nullable byte[] value) throws IOException {
|
||||
return ByteArrayEnumerator.super.enumerate(value);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public byte[] valueOf(int idx) throws IOException {
|
||||
return ByteArrayEnumerator.super.valueOf(idx);
|
||||
}
|
||||
}, ByteSequenceDataExternalizer.INSTANCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int enumerate(@Nullable byte[] value) {
|
||||
try {
|
||||
return myCache != null ? myCache.enumerate(value) : super.enumerate(value);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new BuildDataCorruptedException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public byte[] valueOf(int idx) throws IOException {
|
||||
return myCache != null ? myCache.valueOf(idx) : super.valueOf(idx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
super.close();
|
||||
if (myCache != null) myCache.close();
|
||||
}
|
||||
|
||||
|
||||
private static class ByteSequenceDataExternalizer implements KeyDescriptor<byte[]>, DifferentSerializableBytesImplyNonEqualityPolicy {
|
||||
private static final ByteSequenceDataExternalizer INSTANCE = new ByteSequenceDataExternalizer();
|
||||
|
||||
@Override
|
||||
public void save(@NotNull DataOutput out, byte[] value) throws IOException {
|
||||
out.writeInt(value.length);
|
||||
out.write(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] read(@NotNull DataInput in) throws IOException {
|
||||
final int len = in.readInt();
|
||||
final byte[] buf = new byte[len];
|
||||
in.readFully(buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHashCode(byte[] value) {
|
||||
return Arrays.hashCode(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEqual(byte[] val1, byte[] val2) {
|
||||
return Arrays.equals(val1, val2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* 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.openapi.util.io.FileUtil;
|
||||
import com.intellij.util.io.EnumeratorIntegerDescriptor;
|
||||
import com.intellij.util.io.PersistentStringEnumerator;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.builders.java.dependencyView.*;
|
||||
import org.jetbrains.jps.builders.storage.BuildDataCorruptedException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
|
||||
public class CompilerBackwardReferenceIndex {
|
||||
private static final int VERSION = 0;
|
||||
private final static String FILE_ENUM_TAB = "file.path.enum.tab";
|
||||
private final static String INCOMPLETE_FILES_TAB = "incomplete.files.tab";
|
||||
private final static String USAGES_TAB = "refs.tab";
|
||||
private final static String BACK_USAGES_TAB = "back.refs.tab";
|
||||
private final static String HIERARCHY_TAB = "hierarchy.tab";
|
||||
private final static String BACK_HIERARCHY_TAB = "back.hierarchy.tab";
|
||||
public static final String VERSION_FILE = ".version";
|
||||
|
||||
private final IntObjectPersistentMultiMaplet<LightUsage> myReferenceMap;
|
||||
private final IntIntPersistentMultiMaplet myHierarchyMap;
|
||||
|
||||
private final ObjectObjectPersistentMultiMaplet<LightUsage, Integer> myBackwardReferenceMap;
|
||||
private final IntIntPersistentMultiMaplet myBackwardHierarchyMap;
|
||||
|
||||
private final ByteArrayEnumerator myNameEnumerator;
|
||||
private final PersistentStringEnumerator myFilePathEnumerator;
|
||||
|
||||
private final File myIndicesDir;
|
||||
|
||||
|
||||
public CompilerBackwardReferenceIndex(File buildDir) {
|
||||
myIndicesDir = getIndexDir(buildDir);
|
||||
if (!myIndicesDir.exists() && !myIndicesDir.mkdirs()) {
|
||||
throw new RuntimeException("Can't create dir: " + buildDir.getAbsolutePath());
|
||||
}
|
||||
try {
|
||||
if (versionDiffers(buildDir)) {
|
||||
FileUtil.writeToFile(new File(myIndicesDir, VERSION_FILE), String.valueOf(VERSION));
|
||||
}
|
||||
myFilePathEnumerator = new PersistentStringEnumerator(new File(myIndicesDir, FILE_ENUM_TAB));
|
||||
|
||||
myBackwardReferenceMap = new ObjectObjectPersistentMultiMaplet<LightUsage, Integer>(new File(myIndicesDir, BACK_USAGES_TAB),
|
||||
LightUsage.createDescriptor(),
|
||||
EnumeratorIntegerDescriptor.INSTANCE,
|
||||
new CollectionFactory<Integer>() {
|
||||
@Override
|
||||
public Collection<Integer> create() {
|
||||
return new THashSet<Integer>();
|
||||
}
|
||||
});
|
||||
myBackwardHierarchyMap = new IntIntPersistentMultiMaplet(new File(myIndicesDir, BACK_HIERARCHY_TAB),
|
||||
EnumeratorIntegerDescriptor.INSTANCE);
|
||||
|
||||
myReferenceMap = new IntObjectPersistentMultiMaplet<LightUsage>(new File(myIndicesDir, USAGES_TAB),
|
||||
EnumeratorIntegerDescriptor.INSTANCE,
|
||||
LightUsage.createDescriptor(), new CollectionFactory<LightUsage>() {
|
||||
@Override
|
||||
public Collection<LightUsage> create() {
|
||||
return new THashSet<LightUsage>();
|
||||
}
|
||||
});
|
||||
myHierarchyMap = new IntIntPersistentMultiMaplet(new File(myIndicesDir, HIERARCHY_TAB), EnumeratorIntegerDescriptor.INSTANCE);
|
||||
|
||||
myNameEnumerator = new ByteArrayEnumerator(new File(myIndicesDir, INCOMPLETE_FILES_TAB));
|
||||
}
|
||||
catch (IOException e) {
|
||||
removeIndexFiles(myIndicesDir);
|
||||
throw new BuildDataCorruptedException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ObjectObjectPersistentMultiMaplet<LightUsage, Integer> getBackwardReferenceMap() {
|
||||
return myBackwardReferenceMap;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public IntIntPersistentMultiMaplet getBackwardHierarchyMap() {
|
||||
return myBackwardHierarchyMap;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public IntObjectPersistentMultiMaplet<LightUsage> getReferenceMap() {
|
||||
return myReferenceMap;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public IntIntPersistentMultiMaplet getHierarchyMap() {
|
||||
return myHierarchyMap;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ByteArrayEnumerator getByteSeqEum() {
|
||||
return myNameEnumerator;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PersistentStringEnumerator getFilePathEnumerator() {
|
||||
return myFilePathEnumerator;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
try {
|
||||
myFilePathEnumerator.close();
|
||||
myBackwardHierarchyMap.close();
|
||||
myBackwardReferenceMap.close();
|
||||
myReferenceMap.close();
|
||||
myHierarchyMap.close();
|
||||
myNameEnumerator.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
removeIndexFiles(myIndicesDir);
|
||||
throw new BuildDataCorruptedException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeIndexFiles(File buildDir) {
|
||||
final File indexDir = getIndexDir(buildDir);
|
||||
if (indexDir.exists()) {
|
||||
FileUtil.delete(indexDir);
|
||||
}
|
||||
}
|
||||
|
||||
private static File getIndexDir(@NotNull File buildDir) {
|
||||
return new File(buildDir, "backward-refs");
|
||||
}
|
||||
|
||||
public static boolean exist(@NotNull File buildDir) {
|
||||
return getIndexDir(buildDir).exists();
|
||||
}
|
||||
|
||||
public static boolean versionDiffers(@NotNull File buildDir) {
|
||||
File versionFile = new File(getIndexDir(buildDir), VERSION_FILE);
|
||||
try {
|
||||
return Integer.parseInt(FileUtil.loadFile(versionFile)) != VERSION;
|
||||
}
|
||||
catch (final IOException e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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.sun.tools.javac.util.Convert;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public abstract class CompilerElement {
|
||||
public static final CompilerElement[] EMPTY_ARRAY = new CompilerElement[0];
|
||||
|
||||
@NotNull
|
||||
public abstract LightUsage asUsage(ByteArrayEnumerator byteArrayEnumerator);
|
||||
|
||||
public static class CompilerMethod extends CompilerElement {
|
||||
private final byte[] myJavacClassName;
|
||||
private final byte[] myJavacMethodName;
|
||||
private final int myJavacParameterCount;
|
||||
|
||||
public CompilerMethod(String javacClassName, String javacMethodName, int count) {
|
||||
this(bytes(javacClassName), bytes(javacMethodName), count);
|
||||
}
|
||||
|
||||
CompilerMethod(byte[] javacClassName, byte[] javacMethodName, int javacParameterCount) {
|
||||
myJavacClassName = javacClassName;
|
||||
myJavacMethodName = javacMethodName;
|
||||
myJavacParameterCount = javacParameterCount;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public LightUsage asUsage(ByteArrayEnumerator byteArrayEnumerator) {
|
||||
return new LightUsage.LightMethodUsage(byteArrayEnumerator.enumerate(myJavacClassName),
|
||||
byteArrayEnumerator.enumerate(myJavacMethodName),
|
||||
myJavacParameterCount);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CompilerClass extends CompilerElement {
|
||||
private final byte[] myJavacName;
|
||||
|
||||
public CompilerClass(String name) {
|
||||
this(bytes(name));
|
||||
}
|
||||
|
||||
CompilerClass(byte[] javacName) {
|
||||
myJavacName = javacName;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public LightUsage asUsage(ByteArrayEnumerator byteArrayEnumerator) {
|
||||
return new LightUsage.LightClassUsage(byteArrayEnumerator.enumerate(myJavacName));
|
||||
}
|
||||
}
|
||||
|
||||
public static class CompilerField extends CompilerElement {
|
||||
private final byte[] myJavacClassName;
|
||||
private final byte[] myJavacName;
|
||||
|
||||
public CompilerField(String javacClassName, String name) {
|
||||
this(bytes(javacClassName), bytes(name));
|
||||
}
|
||||
|
||||
CompilerField(byte[] javacClassName, byte[] javacName) {
|
||||
myJavacClassName = javacClassName;
|
||||
myJavacName = javacName;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public LightUsage asUsage(ByteArrayEnumerator byteArrayEnumerator) {
|
||||
return new LightUsage.LightFieldUsage(byteArrayEnumerator.enumerate(myJavacClassName),
|
||||
byteArrayEnumerator.enumerate(myJavacName));
|
||||
}
|
||||
}
|
||||
|
||||
static byte[] bytes(String str) {
|
||||
//TODO
|
||||
return Convert.string2utf(str);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* 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.tools.javac.code.Symbol;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.builders.java.dependencyView.RW;
|
||||
import org.jetbrains.jps.builders.storage.BuildDataCorruptedException;
|
||||
|
||||
import javax.lang.model.element.ElementKind;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
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;
|
||||
|
||||
public final int myOwner;
|
||||
|
||||
protected LightUsage(int owner) {
|
||||
myOwner = owner;
|
||||
}
|
||||
|
||||
public int getOwner() {
|
||||
return myOwner;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public abstract LightUsage override(int ownerOverrider);
|
||||
|
||||
public static class LightMethodUsage extends LightUsage {
|
||||
private final int myName;
|
||||
private final int myParameterCount;
|
||||
|
||||
LightMethodUsage(int owner, int name, int parameterCount) {
|
||||
super(owner);
|
||||
myName = name;
|
||||
myParameterCount = parameterCount;
|
||||
}
|
||||
|
||||
public int getName() {
|
||||
return myName;
|
||||
}
|
||||
|
||||
public int getParameterCount() {
|
||||
return myParameterCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(DataOutput out) {
|
||||
try {
|
||||
out.writeByte(METHOD_MARKER);
|
||||
DataInputOutputUtil.writeINT(out, getOwner());
|
||||
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(int ownerOverrider) {
|
||||
return new LightMethodUsage(ownerOverrider, getName(), getParameterCount());
|
||||
}
|
||||
}
|
||||
|
||||
public static class LightFieldUsage extends LightUsage {
|
||||
private final int myName;
|
||||
|
||||
LightFieldUsage(int owner, int name) {
|
||||
super(owner);
|
||||
myName = name;
|
||||
}
|
||||
|
||||
public int getName() {
|
||||
return myName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(DataOutput out) {
|
||||
try {
|
||||
out.writeByte(FIELD_MARKER);
|
||||
DataInputOutputUtil.writeINT(out, getOwner());
|
||||
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(int ownerOverrider) {
|
||||
return new LightFieldUsage(ownerOverrider, getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class LightClassUsage extends LightUsage {
|
||||
LightClassUsage(int owner) {
|
||||
super(owner);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public LightClassUsage override(int ownerOverrider) {
|
||||
return new LightClassUsage(ownerOverrider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(DataOutput out) {
|
||||
try {
|
||||
out.writeByte(CLASS_MARKER);
|
||||
DataInputOutputUtil.writeINT(out, getOwner());
|
||||
}
|
||||
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 (myOwner != usage.myOwner) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return myOwner;
|
||||
}
|
||||
}
|
||||
|
||||
static KeyDescriptor<LightUsage> createDescriptor() {
|
||||
return new KeyDescriptor<LightUsage>() {
|
||||
@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));
|
||||
}
|
||||
throw new AssertionError();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static byte[] bytes(Symbol symbol) {
|
||||
return symbol.getQualifiedName().toUtf();
|
||||
}
|
||||
|
||||
static LightUsage fromSymbol(Symbol symbol, ByteArrayEnumerator byteArrayEnumerator) {
|
||||
final ElementKind kind = symbol.getKind();
|
||||
if (symbol instanceof Symbol.ClassSymbol) {
|
||||
return new LightClassUsage(id(symbol, byteArrayEnumerator));
|
||||
}
|
||||
else if (symbol instanceof Symbol.VarSymbol) {
|
||||
return new LightFieldUsage(id(symbol.owner, byteArrayEnumerator), id(symbol, byteArrayEnumerator));
|
||||
}
|
||||
else if (symbol instanceof Symbol.MethodSymbol) {
|
||||
int paramCount = ((Symbol.MethodSymbol)symbol).type.getParameterTypes().size();
|
||||
return new LightMethodUsage(id(symbol.owner, byteArrayEnumerator), id(symbol, byteArrayEnumerator), paramCount);
|
||||
}
|
||||
else {
|
||||
throw new AssertionError("unexpected symbol: " + symbol + " class: " + symbol.getClass() + " kind: " + kind);
|
||||
}
|
||||
}
|
||||
|
||||
private static int id(Symbol symbol, ByteArrayEnumerator byteArrayEnumerator) {
|
||||
return byteArrayEnumerator.enumerate(bytes(symbol));
|
||||
}
|
||||
}
|
||||
@@ -16,15 +16,18 @@
|
||||
package org.jetbrains.jps.builders.impl.java;
|
||||
|
||||
import com.intellij.util.ExceptionUtil;
|
||||
import com.sun.source.util.JavacTask;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.builders.java.CannotCreateJavaCompilerException;
|
||||
import org.jetbrains.jps.builders.java.JavaCompilingTool;
|
||||
import org.jetbrains.jps.javac.JavacMain;
|
||||
import org.jetbrains.jps.javac.ast.JavacReferencesCollector;
|
||||
import org.jetbrains.jps.model.java.compiler.JavaCompilers;
|
||||
|
||||
import javax.tools.*;
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@@ -79,4 +82,9 @@ public class JavacCompilerTool extends JavaCompilingTool {
|
||||
public List<String> getDefaultCompilerOptions() {
|
||||
return Collections.singletonList("-implicit:class");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareCompilationTask(@NotNull JavaCompiler.CompilationTask task, @NotNull Collection<String> options) {
|
||||
JavacReferencesCollector.installOn((JavacTask)task);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ import java.io.*;
|
||||
* @author: db
|
||||
* Date: 08.03.11
|
||||
*/
|
||||
class IntIntPersistentMultiMaplet extends IntIntMultiMaplet {
|
||||
public class IntIntPersistentMultiMaplet extends IntIntMultiMaplet {
|
||||
private static final TIntHashSet NULL_COLLECTION = new TIntHashSet();
|
||||
private static final int CACHE_SIZE = 128;
|
||||
private final PersistentHashMap<Integer, TIntHashSet> myMap;
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ import java.util.Collections;
|
||||
* @author: db
|
||||
* Date: 08.03.11
|
||||
*/
|
||||
class IntObjectPersistentMultiMaplet<V> extends IntObjectMultiMaplet<V> {
|
||||
public class IntObjectPersistentMultiMaplet<V> extends IntObjectMultiMaplet<V> {
|
||||
private static final Collection NULL_COLLECTION = Collections.emptySet();
|
||||
private static final int CACHE_SIZE = 128;
|
||||
private final PersistentHashMap<Integer, Collection<V>> myMap;
|
||||
|
||||
+7
-7
@@ -28,7 +28,7 @@ import java.util.*;
|
||||
* @author: db
|
||||
* Date: 03.11.11
|
||||
*/
|
||||
abstract class ObjectObjectMultiMaplet<K, V extends Streamable> implements Streamable {
|
||||
abstract class ObjectObjectMultiMaplet<K, V> implements Streamable {
|
||||
abstract boolean containsKey(final K key);
|
||||
|
||||
abstract Collection<V> get(final K key);
|
||||
@@ -87,12 +87,12 @@ abstract class ObjectObjectMultiMaplet<K, V extends Streamable> implements Strea
|
||||
final List<String> list = new LinkedList<String>();
|
||||
|
||||
for (final V value : b) {
|
||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
final PrintStream s = new PrintStream(baos);
|
||||
|
||||
value.toStream(context, s);
|
||||
|
||||
list.add(baos.toString());
|
||||
if (value instanceof Streamable) {
|
||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
final PrintStream s = new PrintStream(baos);
|
||||
((Streamable) value).toStream(context, s);
|
||||
list.add(baos.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Collections.sort(list);
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ import java.util.Collections;
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 9/10/12
|
||||
*/
|
||||
public class ObjectObjectPersistentMultiMaplet<K, V extends Streamable> extends ObjectObjectMultiMaplet<K, V>{
|
||||
public class ObjectObjectPersistentMultiMaplet<K, V> extends ObjectObjectMultiMaplet<K, V>{
|
||||
private static final Collection NULL_COLLECTION = Collections.emptySet();
|
||||
private static final int CACHE_SIZE = 128;
|
||||
private final PersistentHashMap<K, Collection<V>> myMap;
|
||||
|
||||
@@ -144,7 +144,7 @@ public class ClasspathBootstrap {
|
||||
cp.addAll(getInstrumentationUtilRoots());
|
||||
cp.add(getResourcePath(IXMLBuilder.class)); // nano-xml
|
||||
cp.add(getJpsPluginSystemClassesPath().getAbsolutePath().replace('\\', '/'));
|
||||
|
||||
appendReferenceTypeScannerClasspath(cp);
|
||||
//don't forget to update layoutCommunityJps() in layouts.gant accordingly
|
||||
|
||||
if (!isLauncherUsed) {
|
||||
@@ -161,6 +161,16 @@ public class ClasspathBootstrap {
|
||||
return ContainerUtil.newArrayList(cp);
|
||||
}
|
||||
|
||||
private static void appendReferenceTypeScannerClasspath(Set<String> cp) {
|
||||
try {
|
||||
final String path = getResourcePath(Class.forName("org.jetbrains.jps.javac.ast.Javac8ReferenceTypeScanner"));
|
||||
if (path != null) {
|
||||
cp.add(path);
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
public static void appendJavaCompilerClasspath(Collection<String> cp) {
|
||||
final Class<StandardJavaFileManager> optimizedFileManagerClass = getOptimizedFileManagerClass();
|
||||
if (optimizedFileManagerClass != null) {
|
||||
|
||||
@@ -20,6 +20,7 @@ import org.jetbrains.jps.builders.BuildTargetType;
|
||||
import org.jetbrains.jps.builders.java.JavaModuleBuildTargetType;
|
||||
import org.jetbrains.jps.builders.java.ResourcesTargetType;
|
||||
import org.jetbrains.jps.classFilesIndex.indexer.api.ClassFilesIndicesBuilder;
|
||||
import org.jetbrains.jps.backwardRefs.BackwardReferenceIndexBuilder;
|
||||
import org.jetbrains.jps.incremental.instrumentation.NotNullInstrumentingBuilder;
|
||||
import org.jetbrains.jps.incremental.instrumentation.RmiStubsGenerator;
|
||||
import org.jetbrains.jps.incremental.java.JavaBuilder;
|
||||
@@ -49,7 +50,8 @@ public class JavaBuilderService extends BuilderService {
|
||||
return Arrays.asList(new JavaBuilder(SharedThreadPool.getInstance()),
|
||||
new NotNullInstrumentingBuilder(),
|
||||
new RmiStubsGenerator(),
|
||||
new ClassFilesIndicesBuilder());
|
||||
new ClassFilesIndicesBuilder(),
|
||||
new BackwardReferenceIndexBuilder());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -141,9 +141,7 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
|
||||
@Override
|
||||
public void buildStarted(CompileContext context) {
|
||||
final JpsProject project = context.getProjectDescriptor().getProject();
|
||||
final JpsJavaCompilerConfiguration config = JpsJavaExtensionService.getInstance().getCompilerConfiguration(project);
|
||||
final String compilerId = config == null? JavaCompilers.JAVAC_ID : config.getJavaCompilerId();
|
||||
final String compilerId = getUsedCompilerId(context);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Java compiler ID: " + compilerId);
|
||||
}
|
||||
@@ -746,6 +744,12 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
return true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getUsedCompilerId(CompileContext context) {
|
||||
final JpsProject project = context.getProjectDescriptor().getProject();
|
||||
final JpsJavaCompilerConfiguration config = JpsJavaExtensionService.getInstance().getCompilerConfiguration(project);
|
||||
return config == null ? JavaCompilers.JAVAC_ID : config.getJavaCompilerId();
|
||||
}
|
||||
|
||||
private static void addCrossCompilationOptions(final int compilerSdkVersion, final List<String> options, final CompileContext context, final ModuleChunk chunk) {
|
||||
final JpsJavaCompilerConfiguration compilerConfiguration = JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* 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.javac.ast;
|
||||
|
||||
import com.intellij.util.ReflectionUtil;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.sun.source.tree.Tree;
|
||||
import com.sun.source.util.JavacTask;
|
||||
import com.sun.source.util.TaskEvent;
|
||||
import com.sun.source.util.TaskListener;
|
||||
import com.sun.tools.javac.code.Symbol;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.util.ClientCodeException;
|
||||
import com.sun.tools.javac.util.Name;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.jps.javac.ast.api.JavacFileReferencesRegistrar;
|
||||
import org.jetbrains.jps.javac.ast.api.JavacRefSymbol;
|
||||
import org.jetbrains.jps.service.JpsServiceManager;
|
||||
|
||||
import javax.lang.model.element.ElementKind;
|
||||
import javax.tools.*;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class JavacReferencesCollector {
|
||||
public static void installOn(JavacTask task) {
|
||||
List<JavacFileReferencesRegistrar> fullASTListeners = new SmartList<JavacFileReferencesRegistrar>();
|
||||
List<JavacFileReferencesRegistrar> onlyImportsListeners = new SmartList<JavacFileReferencesRegistrar>();
|
||||
for (JavacFileReferencesRegistrar listener : JpsServiceManager.getInstance().getExtensions(JavacFileReferencesRegistrar.class)) {
|
||||
if (!listener.initialize()) {
|
||||
continue;
|
||||
}
|
||||
(listener.onlyImports() ? onlyImportsListeners : fullASTListeners).add(listener);
|
||||
}
|
||||
|
||||
final JavacFileReferencesRegistrar[] fullASTListenerArray = fullASTListeners.toArray(new JavacFileReferencesRegistrar[fullASTListeners.size()]);
|
||||
final JavacFileReferencesRegistrar[] onlyImportsListenerArray = onlyImportsListeners.toArray(new JavacFileReferencesRegistrar[onlyImportsListeners.size()]);
|
||||
if (fullASTListenerArray.length == 0 && onlyImportsListenerArray.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Method addTaskMethod = ReflectionUtil.getMethod(JavacTask.class, "addTaskListener", TaskListener.class); // jdk >= 8
|
||||
if (addTaskMethod == null) {
|
||||
addTaskMethod = ReflectionUtil.getMethod(JavacTask.class, "setTaskListener", TaskListener.class); // jdk 6-7
|
||||
}
|
||||
assert addTaskMethod != null;
|
||||
|
||||
try {
|
||||
addTaskMethod.invoke(task, new MyTaskListener(fullASTListenerArray, onlyImportsListenerArray));
|
||||
}
|
||||
catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class MyTaskListener implements TaskListener {
|
||||
private JCTree.JCCompilationUnit myCurrentCompilationUnit;
|
||||
private final JavacFileReferencesRegistrar[] myFullASTListeners;
|
||||
private final JavacFileReferencesRegistrar[] myOnlyImportsListeners;
|
||||
private final JavacTreeRefScanner myAstScanner;
|
||||
|
||||
private int myCurrentSize;
|
||||
private Name myAsteriks;
|
||||
|
||||
public MyTaskListener(JavacFileReferencesRegistrar[] fullASTListenerArray, JavacFileReferencesRegistrar[] importsListenerArray) {
|
||||
myFullASTListeners = fullASTListenerArray;
|
||||
myOnlyImportsListeners = importsListenerArray;
|
||||
myAstScanner = JavacTreeRefScanner.createASTScanner();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void started(TaskEvent e) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finished(TaskEvent e) {
|
||||
try {
|
||||
if (e.getKind() == TaskEvent.Kind.ANALYZE) {
|
||||
// javac creates event on each processed class not file
|
||||
if (myCurrentCompilationUnit != e.getCompilationUnit()) {
|
||||
myCurrentCompilationUnit = (JCTree.JCCompilationUnit)e.getCompilationUnit();
|
||||
myCurrentSize = myCurrentCompilationUnit.getTypeDecls().size() - 1;
|
||||
}
|
||||
else {
|
||||
myCurrentSize--;
|
||||
}
|
||||
|
||||
if (myCurrentSize == 0) {
|
||||
final JavaFileObject sourceFile = e.getSourceFile();
|
||||
final Set<JavacRefSymbol> symbols = new THashSet<JavacRefSymbol>();
|
||||
scanImports(myCurrentCompilationUnit, symbols);
|
||||
for (JavacFileReferencesRegistrar listener : myOnlyImportsListeners) {
|
||||
listener.registerReferences(sourceFile, symbols);
|
||||
}
|
||||
if (myFullASTListeners.length != 0) {
|
||||
myAstScanner.scan(myCurrentCompilationUnit, new JavacTreeScannerSink() {
|
||||
@Override
|
||||
public void sinkReference(JavacRefSymbol ref) {
|
||||
symbols.add(ref);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sinkClassDeclaration(Symbol className, Symbol[] supers) {
|
||||
for (JavacFileReferencesRegistrar listener : myFullASTListeners) {
|
||||
listener.registerClassDeclaration(className, supers);
|
||||
}
|
||||
}
|
||||
});
|
||||
for (JavacFileReferencesRegistrar listener : myFullASTListeners) {
|
||||
listener.registerReferences(sourceFile, symbols);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new ClientCodeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private Name getAsteriksFromCurrentNameTable(Name tableRepresentative) {
|
||||
if (myAsteriks == null) {
|
||||
myAsteriks = tableRepresentative.table.fromChars(new char[]{'*'}, 0, 1);
|
||||
}
|
||||
return myAsteriks;
|
||||
}
|
||||
|
||||
private void scanImports(JCTree.JCCompilationUnit compilationUnit, Set<JavacRefSymbol> symbols) {
|
||||
for (JCTree.JCImport anImport : compilationUnit.getImports()) {
|
||||
final JCTree.JCFieldAccess id = (JCTree.JCFieldAccess)anImport.getQualifiedIdentifier();
|
||||
final Symbol sym = id.sym;
|
||||
if (sym == null) {
|
||||
final JCTree.JCFieldAccess classImport = (JCTree.JCFieldAccess)id.getExpression();
|
||||
final Symbol ownerSym = classImport.sym;
|
||||
final Name name = id.getIdentifier();
|
||||
if (name != getAsteriksFromCurrentNameTable(name)) {
|
||||
// member import
|
||||
for (Symbol memberSymbol : ownerSym.members().getElements()) {
|
||||
if (memberSymbol.getSimpleName() == name) {
|
||||
symbols.add(new JavacRefSymbol(memberSymbol, Tree.Kind.IMPORT));
|
||||
}
|
||||
}
|
||||
}
|
||||
collectClassImports(ownerSym, symbols);
|
||||
} else {
|
||||
// class import
|
||||
collectClassImports(sym, symbols);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void collectClassImports(Symbol baseImport, Set<JavacRefSymbol> collector) {
|
||||
for (Symbol symbol = baseImport;
|
||||
symbol != null && symbol.getKind() != ElementKind.PACKAGE;
|
||||
symbol = symbol.owner) {
|
||||
collector.add(new JavacRefSymbol(symbol, Tree.Kind.IMPORT));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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.javac.ast;
|
||||
|
||||
import com.sun.source.tree.*;
|
||||
import com.sun.source.util.TreeScanner;
|
||||
import com.sun.tools.javac.code.Symbol;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import org.jetbrains.jps.javac.ast.api.JavacRefSymbol;
|
||||
|
||||
import javax.lang.model.element.ElementKind;
|
||||
import javax.lang.model.type.TypeKind;
|
||||
import java.util.List;
|
||||
|
||||
class JavacTreeRefScanner extends TreeScanner<Tree, JavacTreeScannerSink> {
|
||||
private static final Symbol[] EMPTY_SYMBOL_ARRAY = new Symbol[0];
|
||||
|
||||
@Override
|
||||
public Tree visitCompilationUnit(CompilationUnitTree node, JavacTreeScannerSink sink) {
|
||||
scan(node.getPackageAnnotations(), sink);
|
||||
scan(node.getTypeDecls(), sink);
|
||||
return node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tree visitIdentifier(IdentifierTree node, JavacTreeScannerSink sink) {
|
||||
final JCTree.JCIdent javacIdentifier = (JCTree.JCIdent)node;
|
||||
final Type type = javacIdentifier.type;
|
||||
if (type == null) {
|
||||
return null;
|
||||
}
|
||||
if (type.getKind() == TypeKind.PACKAGE) {
|
||||
return null;
|
||||
}
|
||||
final Symbol sym = javacIdentifier.sym;
|
||||
if (sym.getKind() == ElementKind.PARAMETER ||
|
||||
sym.getKind() == ElementKind.LOCAL_VARIABLE ||
|
||||
sym.getKind() == ElementKind.FIELD ||
|
||||
sym.getKind() == ElementKind.EXCEPTION_PARAMETER ||
|
||||
sym.getKind() == ElementKind.TYPE_PARAMETER) {
|
||||
return null;
|
||||
}
|
||||
sink.sinkReference(new JavacRefSymbol(sym, Tree.Kind.IDENTIFIER));
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tree visitVariable(VariableTree node, JavacTreeScannerSink sink) {
|
||||
final Symbol.VarSymbol sym = ((JCTree.JCVariableDecl)node).sym;
|
||||
if (sym.getKind() == ElementKind.FIELD) {
|
||||
sink.sinkReference(new JavacRefSymbol(sym, Tree.Kind.VARIABLE));
|
||||
}
|
||||
return super.visitVariable(node, sink);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tree visitMemberSelect(MemberSelectTree node, JavacTreeScannerSink sink) {
|
||||
final Symbol sym = ((JCTree.JCFieldAccess)node).sym;
|
||||
if (sym.getKind() != ElementKind.PACKAGE) {
|
||||
sink.sinkReference(new JavacRefSymbol(sym, Tree.Kind.MEMBER_SELECT));
|
||||
}
|
||||
return super.visitMemberSelect(node, sink);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tree visitMethod(MethodTree node, JavacTreeScannerSink sink) {
|
||||
final Symbol.MethodSymbol sym = ((JCTree.JCMethodDecl)node).sym;
|
||||
sink.sinkReference(new JavacRefSymbol(sym, Tree.Kind.METHOD));
|
||||
return super.visitMethod(node, sink);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Tree visitClass(ClassTree node, JavacTreeScannerSink sink) {
|
||||
Symbol.ClassSymbol sym = ((JCTree.JCClassDecl)node).sym;
|
||||
sink.sinkReference(new JavacRefSymbol(sym, Tree.Kind.CLASS));
|
||||
|
||||
Type superclass = sym.getSuperclass();
|
||||
List<Type> interfaces = sym.getInterfaces();
|
||||
|
||||
final Symbol[] supers;
|
||||
if (superclass != Type.noType) {
|
||||
supers = new Symbol[interfaces.size() + 1];
|
||||
supers[interfaces.size()] = superclass.asElement();
|
||||
} else {
|
||||
supers = interfaces.isEmpty() ? EMPTY_SYMBOL_ARRAY : new Symbol[interfaces.size()];
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
for (Type anInterface : interfaces) {
|
||||
supers[i++] = anInterface.asElement();
|
||||
}
|
||||
sink.sinkClassDeclaration(sym, supers);
|
||||
|
||||
return super.visitClass(node, sink);
|
||||
}
|
||||
|
||||
static JavacTreeRefScanner createASTScanner() {
|
||||
try {
|
||||
Class aClass = Class.forName("org.jetbrains.jps.javac.ast.Javac8RefScanner");
|
||||
return (JavacTreeRefScanner) aClass.newInstance();
|
||||
}
|
||||
catch (Throwable ignored) {
|
||||
return new JavacTreeRefScanner();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.javac.ast;
|
||||
|
||||
import com.sun.tools.javac.code.Symbol;
|
||||
import org.jetbrains.jps.javac.ast.api.JavacRefSymbol;
|
||||
|
||||
interface JavacTreeScannerSink {
|
||||
|
||||
void sinkReference(JavacRefSymbol ref);
|
||||
|
||||
void sinkClassDeclaration(Symbol className, Symbol[] supers);
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.javac.ast.api;
|
||||
|
||||
import com.sun.tools.javac.code.Symbol;
|
||||
|
||||
import javax.tools.*;
|
||||
import java.util.Set;
|
||||
|
||||
public interface JavacFileReferencesRegistrar {
|
||||
|
||||
boolean initialize();
|
||||
|
||||
boolean onlyImports();
|
||||
|
||||
void registerReferences(JavaFileObject file, Set<JavacRefSymbol> refs);
|
||||
|
||||
void registerClassDeclaration(Symbol className, Symbol[] supers);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.javac.ast.api;
|
||||
|
||||
import com.sun.source.tree.Tree;
|
||||
import com.sun.tools.javac.code.Symbol;
|
||||
|
||||
public class JavacRefSymbol {
|
||||
|
||||
private final Symbol mySymbol;
|
||||
private final Tree.Kind myPlaceKind;
|
||||
|
||||
public JavacRefSymbol(Symbol symbol, Tree.Kind kind) {
|
||||
mySymbol = symbol;
|
||||
myPlaceKind = kind;
|
||||
}
|
||||
|
||||
public Symbol getSymbol() {
|
||||
return mySymbol;
|
||||
}
|
||||
|
||||
public Tree.Kind getPlaceKind() {
|
||||
return myPlaceKind;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
class Array {
|
||||
|
||||
void method(Foo[] param) {
|
||||
Bar[] bars = null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
class Bar {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
class Foo {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
Backward Hierarchy:
|
||||
java.lang.Object -> Array Bar Foo
|
||||
|
||||
Backward References:
|
||||
Array in Array
|
||||
Array.<init>(0) in Array
|
||||
Array.method(1) in Array
|
||||
Bar in Array Bar
|
||||
Bar.<init>(0) in Bar
|
||||
Foo in Array Foo
|
||||
Foo.<init>(0) in Foo
|
||||
java.lang.Object.<init>(0) in Array Bar Foo
|
||||
@@ -0,0 +1,11 @@
|
||||
public class Bar {
|
||||
public static final boolean DEBUG = false;
|
||||
|
||||
public static void m() {
|
||||
if (DEBUG) {
|
||||
System.out.println("I'm dead");
|
||||
} else {
|
||||
new java.util.ArrayList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
Backward Hierarchy:
|
||||
java.lang.Object -> Bar
|
||||
|
||||
Backward References:
|
||||
Bar in Bar
|
||||
Bar.<init>(0) in Bar
|
||||
Bar.DEBUG in Bar
|
||||
Bar.m(0) in Bar
|
||||
java.io.PrintStream.println(1) in Bar
|
||||
java.lang.Object.<init>(0) in Bar
|
||||
java.lang.System in Bar
|
||||
java.lang.System.out in Bar
|
||||
java.util.ArrayList in Bar
|
||||
@@ -0,0 +1,7 @@
|
||||
class Inner {
|
||||
|
||||
void m() {
|
||||
System.out.println("ololo");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
Backward Hierarchy:
|
||||
java.lang.Object -> Inner
|
||||
|
||||
Backward References:
|
||||
Inner in Bar bar
|
||||
Inner.<init>(0) in Bar bar
|
||||
Inner.m(0) in Bar bar
|
||||
java.io.PrintStream.println(1) in Bar bar
|
||||
java.lang.Object.<init>(0) in Bar bar
|
||||
java.lang.System in Bar bar
|
||||
java.lang.System.out in Bar bar
|
||||
@@ -0,0 +1,11 @@
|
||||
Backward Hierarchy:
|
||||
java.lang.Object -> Inner
|
||||
|
||||
Backward References:
|
||||
Inner in Bar
|
||||
Inner.<init>(0) in Bar
|
||||
Inner.m(0) in Bar
|
||||
java.io.PrintStream.println(1) in Bar
|
||||
java.lang.Object.<init>(0) in Bar
|
||||
java.lang.System in Bar
|
||||
java.lang.System.out in Bar
|
||||
@@ -0,0 +1,6 @@
|
||||
class Bar {
|
||||
static void m(FooImpl f) {
|
||||
System.out.println(FooImpl.TITLE);
|
||||
System.out.println(f.getSomeText());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
class Bar {
|
||||
static void m(FooImpl f) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
interface Foo {
|
||||
String getSomeText();
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
class FooImpl implements Foo {
|
||||
static String TITLE = "Foo.title";
|
||||
|
||||
public String getSomeText() {
|
||||
return "text";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
class FooImpl {
|
||||
static String TITLE = "Foo.title";
|
||||
|
||||
public String getSomeText() {
|
||||
return "text";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
Backward Hierarchy:
|
||||
Foo -> FooImpl
|
||||
java.lang.Object -> Bar FooImpl
|
||||
|
||||
Backward References:
|
||||
Bar in Bar
|
||||
Bar.<init>(0) in Bar
|
||||
Bar.m(1) in Bar
|
||||
Foo in Foo FooImpl
|
||||
Foo.getSomeText(0) in Foo
|
||||
FooImpl in Bar FooImpl
|
||||
FooImpl.<init>(0) in FooImpl
|
||||
FooImpl.TITLE in FooImpl
|
||||
FooImpl.getSomeText(0) in FooImpl
|
||||
java.lang.Object.<init>(0) in Bar FooImpl
|
||||
java.lang.String in Foo FooImpl
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
Backward Hierarchy:
|
||||
Foo -> FooImpl
|
||||
java.lang.Object -> Bar FooImpl
|
||||
|
||||
Backward References:
|
||||
Bar in Bar
|
||||
Bar.<init>(0) in Bar
|
||||
Bar.m(1) in Bar
|
||||
Foo in Foo
|
||||
Foo.getSomeText(0) in Foo
|
||||
FooImpl in Bar FooImpl
|
||||
FooImpl.<init>(0) in FooImpl
|
||||
FooImpl.TITLE in FooImpl
|
||||
FooImpl.getSomeText(0) in FooImpl
|
||||
java.lang.Object.<init>(0) in Bar FooImpl
|
||||
java.lang.String in Foo FooImpl
|
||||
@@ -0,0 +1,19 @@
|
||||
Backward Hierarchy:
|
||||
Foo -> FooImpl
|
||||
java.lang.Object -> Bar FooImpl
|
||||
|
||||
Backward References:
|
||||
Bar in Bar
|
||||
Bar.<init>(0) in Bar
|
||||
Bar.m(1) in Bar
|
||||
Foo in Foo FooImpl
|
||||
Foo.getSomeText(0) in Foo
|
||||
FooImpl in Bar FooImpl
|
||||
FooImpl.<init>(0) in FooImpl
|
||||
FooImpl.TITLE in Bar FooImpl
|
||||
FooImpl.getSomeText(0) in Bar FooImpl
|
||||
java.io.PrintStream.println(1) in Bar
|
||||
java.lang.Object.<init>(0) in Bar FooImpl
|
||||
java.lang.String in Foo FooImpl
|
||||
java.lang.System in Bar
|
||||
java.lang.System.out in Bar
|
||||
@@ -0,0 +1,7 @@
|
||||
Backward Hierarchy:
|
||||
java.lang.Object -> myPackage.A
|
||||
|
||||
Backward References:
|
||||
java.lang.Deprecated in package-info
|
||||
myPackage.A in package-info
|
||||
myPackage.A.<init>(0) in package-info
|
||||
@@ -0,0 +1,6 @@
|
||||
@Deprecated
|
||||
package myPackage;
|
||||
|
||||
class A {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import java.util.List;
|
||||
|
||||
class TypeParam {
|
||||
|
||||
void method(List<String> strings) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
Backward Hierarchy:
|
||||
java.lang.Object -> TypeParam
|
||||
|
||||
Backward References:
|
||||
TypeParam in TypeParam
|
||||
TypeParam.<init>(0) in TypeParam
|
||||
TypeParam.method(1) in TypeParam
|
||||
java.lang.Object.<init>(0) in TypeParam
|
||||
java.lang.String in TypeParam
|
||||
java.util.List in TypeParam
|
||||
@@ -0,0 +1,12 @@
|
||||
import java.util.List;
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Collections.EMPTY_LIST;
|
||||
import java.util.ArrayList.*;
|
||||
import static java.util.LinkedList.*;
|
||||
|
||||
/**
|
||||
* {@link Collection#add(Object)}
|
||||
*/
|
||||
public class Bar {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
Backward Hierarchy:
|
||||
java.lang.Object -> Bar
|
||||
|
||||
Backward References:
|
||||
Bar in Bar
|
||||
Bar.<init>(0) in Bar
|
||||
java.lang.Object.<init>(0) in Bar
|
||||
java.util.ArrayList in Bar
|
||||
java.util.Collections in Bar
|
||||
java.util.Collections.EMPTY_LIST in Bar
|
||||
java.util.Collections.emptyList(0) in Bar
|
||||
java.util.LinkedList in Bar
|
||||
java.util.List in Bar
|
||||
@@ -0,0 +1,8 @@
|
||||
import static com.ru.Some.I1.I2.I3;
|
||||
import static com.ru.Some3.CONST;
|
||||
import static com.ru.Some2.I1.I2.utilityMethod;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.ru;
|
||||
|
||||
public class Some {
|
||||
|
||||
public static class I1 {
|
||||
|
||||
public static class I2 {
|
||||
|
||||
public static class I3 {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.ru;
|
||||
|
||||
public class Some2 {
|
||||
|
||||
public static class I1 {
|
||||
|
||||
public static class I2 {
|
||||
|
||||
public static void utilityMethod() {
|
||||
|
||||
}
|
||||
|
||||
public static void utilityMethod(int i) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.ru;
|
||||
|
||||
public class Some3 {
|
||||
public static final int CONST = 10;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
Backward Hierarchy:
|
||||
java.lang.Object -> Main com.ru.Some com.ru.Some.I1 com.ru.Some.I1.I2 com.ru.Some.I1.I2.I3 com.ru.Some2 com.ru.Some2.I1 com.ru.Some2.I1.I2 com.ru.Some3
|
||||
|
||||
Backward References:
|
||||
Main in Main
|
||||
Main.<init>(0) in Main
|
||||
Main.main(1) in Main
|
||||
com.ru.Some in Main Some
|
||||
com.ru.Some.<init>(0) in Some
|
||||
com.ru.Some.I1 in Main Some
|
||||
com.ru.Some.I1.<init>(0) in Some
|
||||
com.ru.Some.I1.I2 in Main Some
|
||||
com.ru.Some.I1.I2.<init>(0) in Some
|
||||
com.ru.Some.I1.I2.I3 in Main Some
|
||||
com.ru.Some.I1.I2.I3.<init>(0) in Some
|
||||
com.ru.Some2 in Main Some2
|
||||
com.ru.Some2.<init>(0) in Some2
|
||||
com.ru.Some2.I1 in Main Some2
|
||||
com.ru.Some2.I1.<init>(0) in Some2
|
||||
com.ru.Some2.I1.I2 in Main Some2
|
||||
com.ru.Some2.I1.I2.<init>(0) in Some2
|
||||
com.ru.Some2.I1.I2.utilityMethod(0) in Main Some2
|
||||
com.ru.Some2.I1.I2.utilityMethod(1) in Main Some2
|
||||
com.ru.Some3 in Main Some3
|
||||
com.ru.Some3.<init>(0) in Some3
|
||||
com.ru.Some3.CONST in Main Some3
|
||||
java.lang.Object.<init>(0) in Main Some Some2 Some3
|
||||
java.lang.String in Main
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.references
|
||||
|
||||
import com.intellij.openapi.application.ex.PathManagerEx
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
|
||||
class ReferenceIndexTest : ReferenceIndexTestBase() {
|
||||
override fun getTestDataRootPath(): String {
|
||||
return FileUtil.toCanonicalPath(PathManagerEx.findFileUnderCommunityHome("jps/jps-builders/testData/referencesIndex").absolutePath, '/')
|
||||
}
|
||||
|
||||
fun testIncrementalIndexUpdate() {
|
||||
assertIndexOnRebuild("Bar.java", "Foo.java", "FooImpl.java")
|
||||
changeFileContent("Bar.java", "Bar_1.java")
|
||||
buildAllModules()
|
||||
assertIndexEquals("afterMakeIndex.txt")
|
||||
changeFileContent("FooImpl.java", "FooImpl_2.java")
|
||||
buildAllModules()
|
||||
assertIndexEquals("afterSecondMakeIndex.txt")
|
||||
}
|
||||
|
||||
fun testFileCaseOnlyRename() {
|
||||
assertIndexOnRebuild("Bar.java")
|
||||
renameFile("Bar.java", "bar.java")
|
||||
buildAllModules()
|
||||
assertIndexEquals("afterRename.txt")
|
||||
}
|
||||
|
||||
fun testUnusedImports() {
|
||||
assertIndexOnRebuild("Bar.java")
|
||||
}
|
||||
|
||||
fun testUnusedImports2() {
|
||||
assertIndexOnRebuild("Main.java",
|
||||
"com/ru/Some.java",
|
||||
"com/ru/Some2.java",
|
||||
"com/ru/Some3.java")
|
||||
}
|
||||
|
||||
fun testDeadCode() {
|
||||
assertIndexOnRebuild("Bar.java")
|
||||
}
|
||||
|
||||
fun testPackageInfo() {
|
||||
assertIndexOnRebuild("myPackage/package-info.java")
|
||||
}
|
||||
|
||||
fun testArrayRefs() {
|
||||
assertIndexOnRebuild("Array.java", "Foo.java", "Bar.java")
|
||||
}
|
||||
|
||||
fun testTypeParameterRefs() {
|
||||
assertIndexOnRebuild("TypeParam.java")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* 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.references
|
||||
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.vfs.CharsetToolkit
|
||||
import com.intellij.util.PathUtil
|
||||
import com.sun.tools.javac.util.Convert
|
||||
import org.jetbrains.jps.builders.JpsBuildTestCase
|
||||
import org.jetbrains.jps.builders.TestProjectBuilderLogger
|
||||
import org.jetbrains.jps.builders.logging.BuildLoggingManager
|
||||
import org.jetbrains.jps.backwardRefs.ByteArrayEnumerator
|
||||
import org.jetbrains.jps.backwardRefs.CompilerBackwardReferenceIndex
|
||||
import org.jetbrains.jps.backwardRefs.LightUsage
|
||||
import org.jetbrains.jps.backwardRefs.BackwardReferenceIndexWriter
|
||||
import java.io.File
|
||||
|
||||
abstract class ReferenceIndexTestBase : JpsBuildTestCase() {
|
||||
public override fun setUp() {
|
||||
super.setUp()
|
||||
System.setProperty(BackwardReferenceIndexWriter.PROP_KEY, true.toString())
|
||||
}
|
||||
|
||||
public override fun tearDown() {
|
||||
super.tearDown()
|
||||
System.clearProperty(BackwardReferenceIndexWriter.PROP_KEY)
|
||||
}
|
||||
|
||||
protected fun assertIndexOnRebuild(vararg files: String) {
|
||||
var representativeFile: String? = null
|
||||
for (file in files) {
|
||||
val addedFile = addFile(file)
|
||||
if (representativeFile == null) {
|
||||
representativeFile = addedFile
|
||||
}
|
||||
}
|
||||
addModule("m", PathUtil.getParentPath(representativeFile!!))
|
||||
rebuildAllModules()
|
||||
assertIndexEquals("initialIndex.txt")
|
||||
}
|
||||
|
||||
protected fun renameFile(fileToRename: String, newName: String) {
|
||||
rename(orCreateProjectDir.path + "/m/" + fileToRename, newName)
|
||||
}
|
||||
|
||||
protected fun changeFileContent(name: String, changesSourceFile: String) {
|
||||
changeFile("m/" + name, FileUtil.loadFile(File(testDataRootPath + "/" + getTestName(true) + "/" + changesSourceFile), CharsetToolkit.UTF8_CHARSET))
|
||||
}
|
||||
|
||||
protected fun addFile(name: String): String {
|
||||
return createFile("m/" + name, FileUtil.loadFile(File(getTestDataPath() + name), CharsetToolkit.UTF8_CHARSET))
|
||||
}
|
||||
|
||||
|
||||
protected fun assertIndexEquals(expectedIndexDumpFile: String) {
|
||||
assertSameLinesWithFile(testDataRootPath + "/" + getTestName(true) + "/" + expectedIndexDumpFile, indexAsText())
|
||||
}
|
||||
|
||||
protected fun indexAsText(): String {
|
||||
val pd = createProjectDescriptor(BuildLoggingManager(TestProjectBuilderLogger()))
|
||||
val manager = pd.dataManager
|
||||
val buildDir = manager.dataPaths.dataStorageRoot
|
||||
val index = CompilerBackwardReferenceIndex(buildDir)
|
||||
|
||||
try {
|
||||
val fileEnumerator = index.filePathEnumerator
|
||||
val nameEnumerator = index.byteSeqEum
|
||||
|
||||
val result = StringBuilder()
|
||||
result.append("Backward Hierarchy:\n")
|
||||
val hierarchyText = mutableListOf<String>()
|
||||
index.backwardHierarchyMap.forEachEntry { superClass, inheritors ->
|
||||
val superClassName = superClass.asName(nameEnumerator)
|
||||
val inheritorsText = mutableListOf<String>()
|
||||
inheritors.forEach { id ->
|
||||
inheritorsText.add(id.asName(nameEnumerator))
|
||||
true
|
||||
}
|
||||
inheritorsText.sort()
|
||||
hierarchyText.add(superClassName + " -> " + inheritorsText.joinToString(separator = " "))
|
||||
true
|
||||
}
|
||||
hierarchyText.sort()
|
||||
result.append(hierarchyText.joinToString(separator = "\n"))
|
||||
|
||||
result.append("\n\nBackward References:\n")
|
||||
val referencesText = mutableListOf<String>()
|
||||
index.backwardReferenceMap.forEachEntry { usage, files ->
|
||||
val referents = mutableListOf<String>()
|
||||
files.forEach { id ->
|
||||
val file = File(fileEnumerator.valueOf(id))
|
||||
val fileName = FileUtil.getNameWithoutExtension(file)
|
||||
referents.add(fileName)
|
||||
}
|
||||
referents.sort()
|
||||
referencesText.add(usage.asText(nameEnumerator) + " in " + referents.joinToString(separator = " "))
|
||||
true
|
||||
}
|
||||
referencesText.sort()
|
||||
result.append(referencesText.joinToString(separator = "\n"))
|
||||
|
||||
return result.toString()
|
||||
} finally {
|
||||
index.close()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getTestDataPath() = testDataRootPath + "/" + getTestName(true) + "/"
|
||||
|
||||
fun Int.asName(byteArrayEnumerator: ByteArrayEnumerator): String = Convert.utf2string(
|
||||
byteArrayEnumerator.valueOf(this))
|
||||
|
||||
fun LightUsage.asText(byteArrayEnumerator: ByteArrayEnumerator): String =
|
||||
when (this) {
|
||||
is LightUsage.LightMethodUsage -> this.owner.asName(byteArrayEnumerator) + "." + this.name.asName(
|
||||
byteArrayEnumerator) + "(" + this.parameterCount + ")"
|
||||
is LightUsage.LightFieldUsage -> this.owner.asName(byteArrayEnumerator) + "." + this.name.asName(byteArrayEnumerator)
|
||||
is LightUsage.LightClassUsage -> this.owner.asName(byteArrayEnumerator)
|
||||
else -> throw UnsupportedOperationException()
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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.find.bytecode;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.UseScopeOptimizer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class CompilerReferenceScopeOptimizer extends UseScopeOptimizer {
|
||||
@Nullable
|
||||
@Override
|
||||
public GlobalSearchScope getScopeToExclude(@NotNull PsiElement element) {
|
||||
return CompilerReferenceService.getInstance(element.getProject()).getScopeWithoutReferences(element);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.find.bytecode;
|
||||
|
||||
import com.intellij.openapi.components.AbstractProjectComponent;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.registry.RegistryValue;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public abstract class CompilerReferenceService extends AbstractProjectComponent {
|
||||
public static final RegistryValue IS_ENABLED_KEY = Registry.get("bytecode.ref.index");
|
||||
|
||||
protected CompilerReferenceService(Project project) {
|
||||
super(project);
|
||||
}
|
||||
|
||||
public static CompilerReferenceService getInstance(@NotNull Project project) {
|
||||
return project.getComponent(CompilerReferenceService.class);
|
||||
}
|
||||
|
||||
public abstract GlobalSearchScope getScopeWithoutReferences(@NotNull PsiElement element);
|
||||
|
||||
public static boolean isEnabled() {
|
||||
return IS_ENABLED_KEY.asBoolean();
|
||||
}
|
||||
}
|
||||
@@ -862,3 +862,7 @@ low.memory.watcher.sync.description=Whether LowMemoryWatcher runnables should be
|
||||
|
||||
typing.freeze.report.dumps=false
|
||||
typing.freeze.report.dumps.description=Automatically reports thread dumps to our statistics server
|
||||
|
||||
bytecode.ref.index=false
|
||||
bytecode.ref.index.description=Enables find usages using references from bytecode
|
||||
bytecode.ref.index.restartRequired=true
|
||||
@@ -74,6 +74,11 @@
|
||||
<implementation-class>com.intellij.codeInsight.daemon.impl.ParameterHintsPassFactory</implementation-class>
|
||||
<skipForDefaultProject/>
|
||||
</component>
|
||||
|
||||
<component>
|
||||
<interface-class>com.intellij.find.bytecode.CompilerReferenceService</interface-class>
|
||||
<implementation-class>com.intellij.compiler.CompilerReferenceServiceImpl</implementation-class>
|
||||
</component>
|
||||
</project-components>
|
||||
|
||||
<extensionPoints>
|
||||
@@ -1797,6 +1802,8 @@
|
||||
<library.javaSourceRootDetector implementation="com.intellij.openapi.roots.ui.configuration.LibraryJavaSourceRootDetector"/>
|
||||
|
||||
<fileBasedIndex implementation="com.intellij.psi.impl.search.JavaNullMethodArgumentIndex"/>
|
||||
|
||||
<useScopeOptimizer implementation="com.intellij.find.bytecode.CompilerReferenceScopeOptimizer"/>
|
||||
</extensions>
|
||||
|
||||
<actions>
|
||||
|
||||
@@ -370,7 +370,7 @@
|
||||
<projectStructure.sourceRootEditHandler implementation="com.intellij.openapi.roots.ui.configuration.JavaTestResourceRootEditHandler"/>
|
||||
|
||||
<buildProcess.parametersProvider implementation="com.intellij.compiler.classFilesIndex.api.index.ClassFilesIndexerBuilderParametersProvider"/>
|
||||
|
||||
<buildProcess.parametersProvider implementation="com.intellij.compiler.CompilerReferenceIndexBuildParametersProvider"/>
|
||||
</extensions>
|
||||
<extensions defaultExtensionNs="org.jetbrains">
|
||||
<webServerRootsProvider implementation="org.jetbrains.builtInWebServer.ArtifactWebServerRootsProvider" order="last"/>
|
||||
|
||||
Reference in New Issue
Block a user