javac ast refs index

This commit is contained in:
Dmitry Batkovich
2016-09-22 19:07:38 +03:00
parent 81fc6960fe
commit 04a816cfb8
76 changed files with 2763 additions and 16 deletions
+2
View File
@@ -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);
}
@@ -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() {
}
}
@@ -0,0 +1,8 @@
public class Bar {
public String getMyName() {
return "Bar...";
};
}
@@ -0,0 +1,5 @@
public class Baz {
public void main(FooImpl f) {
System.out.println(f.getMyName());
}
}
@@ -0,0 +1,5 @@
public interface Foo {
String getM<caret>yName();
}
@@ -0,0 +1,7 @@
public class FooImpl implements Foo {
public String getMyName() {
return "FooImpl is my name";
};
}
@@ -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
@@ -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
@@ -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;
}
}
@@ -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);
}
}
}
@@ -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);
}
}
@@ -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;
@@ -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;
@@ -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);
@@ -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);
}
@@ -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
@@ -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()
}
}
@@ -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
+7
View File
@@ -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>
+1 -1
View File
@@ -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"/>