mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge branch 'db/implicit-to-string'
# Conflicts: # java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerReferenceServiceImpl.java # java/java-indexing-impl/src/com/intellij/compiler/CompilerReferenceService.java # jps/jps-builders-6/src/org/jetbrains/jps/javac/ast/JavacTreeRefScanner.java # jps/jps-builders/testSrc/org/jetbrains/references/ReferenceIndexTest.kt
This commit is contained in:
+18
-15
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.
|
||||
*/
|
||||
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.compiler.backwardRefs;
|
||||
|
||||
import com.intellij.compiler.server.BuildManager;
|
||||
@@ -74,6 +60,23 @@ class CompilerReferenceReader {
|
||||
return set;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
TIntHashSet findFileIdsWithImplicitToString(@NotNull LightRef ref) throws StorageException {
|
||||
TIntHashSet result = new TIntHashSet();
|
||||
myIndex.get(CompilerIndices.IMPLICIT_TO_STRING).getData(ref).forEach(
|
||||
new ValueContainer.ContainerAction<Void>() {
|
||||
@Override
|
||||
public boolean perform(int id, Void value) {
|
||||
final VirtualFile file = findFile(id);
|
||||
if (file != null) {
|
||||
result.add(((VirtualFileWithId)file).getId());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return two maps of classes grouped per file
|
||||
*
|
||||
|
||||
+44
-10
@@ -162,12 +162,29 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceServiceEx imp
|
||||
|
||||
try {
|
||||
return CachedValuesManager.getCachedValue(element,
|
||||
() -> CachedValueProvider.Result.create(calculateScopeWithoutReferences(element),
|
||||
PsiModificationTracker.MODIFICATION_COUNT,
|
||||
this));
|
||||
() -> CachedValueProvider.Result.create(buildScopeWithoutReferences(getReferentFileIds(element)),
|
||||
PsiModificationTracker.MODIFICATION_COUNT,
|
||||
this));
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
return onException(e, "scope without code references");
|
||||
catch (RuntimeException e1) {
|
||||
return onException(e1, "scope without code references");
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public GlobalSearchScope getScopeWithoutImplicitToStringCodeReferences(@NotNull PsiElement aClass) {
|
||||
if (!isServiceEnabledFor(aClass)) return null;
|
||||
|
||||
try {
|
||||
return CachedValuesManager.getCachedValue(aClass,
|
||||
() -> CachedValueProvider.Result.create(
|
||||
buildScopeWithoutReferences(getReferentFileIdsViaImplicitToString(aClass)),
|
||||
PsiModificationTracker.MODIFICATION_COUNT,
|
||||
this));
|
||||
}
|
||||
catch (RuntimeException e1) {
|
||||
return onException(e1, "scope without implicit toString references");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -516,8 +533,7 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceServiceEx imp
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private GlobalSearchScope calculateScopeWithoutReferences(@NotNull PsiElement element) {
|
||||
TIntHashSet referentFileIds = getReferentFileIds(element);
|
||||
private GlobalSearchScope buildScopeWithoutReferences(@Nullable TIntHashSet referentFileIds) {
|
||||
if (referentFileIds == null) return null;
|
||||
|
||||
return getScopeRestrictedByFileTypes(new ScopeWithoutReferencesOnCompilation(referentFileIds, myProjectFileIndex).intersectWith(notScope(
|
||||
@@ -527,7 +543,19 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceServiceEx imp
|
||||
|
||||
@Nullable
|
||||
private TIntHashSet getReferentFileIds(@NotNull PsiElement element) {
|
||||
final CompilerElementInfo compilerElementInfo = asCompilerElements(element, true, true);
|
||||
return getReferentFileIds(element, true, (ref, elementPlace) -> myReader.findReferentFileIds(ref, elementPlace == ElementPlace.SRC));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private TIntHashSet getReferentFileIdsViaImplicitToString(@NotNull PsiElement element) {
|
||||
return getReferentFileIds(element, false, (ref, elementPlace) -> myReader.findFileIdsWithImplicitToString(ref));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private TIntHashSet getReferentFileIds(@NotNull PsiElement element,
|
||||
boolean buildHierarchyForLibraryElements,
|
||||
@NotNull ReferentFileSearcher referentFileSearcher) {
|
||||
final CompilerElementInfo compilerElementInfo = asCompilerElements(element, buildHierarchyForLibraryElements, true);
|
||||
if (compilerElementInfo == null) return null;
|
||||
|
||||
if (!myReadDataLock.tryLock()) return null;
|
||||
@@ -536,14 +564,14 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceServiceEx imp
|
||||
TIntHashSet referentFileIds = new TIntHashSet();
|
||||
for (LightRef ref : compilerElementInfo.searchElements) {
|
||||
try {
|
||||
final TIntHashSet referents = myReader.findReferentFileIds(ref, compilerElementInfo.place == ElementPlace.SRC);
|
||||
final TIntHashSet referents = referentFileSearcher.findReferentFiles(ref, compilerElementInfo.place);
|
||||
if (referents == null) return null;
|
||||
referentFileIds.addAll(referents.toArray());
|
||||
}
|
||||
catch (StorageException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return referentFileIds;
|
||||
|
||||
} finally {
|
||||
@@ -845,4 +873,10 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceServiceEx imp
|
||||
COMPILATION_FINISHED,
|
||||
UP_TO_DATE_CACHE
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
private interface ReferentFileSearcher {
|
||||
@Nullable
|
||||
TIntHashSet findReferentFiles(@NotNull LightRef ref, @NotNull ElementPlace place) throws StorageException;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.
|
||||
*/
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.find.findUsages;
|
||||
|
||||
import com.intellij.find.FindBundle;
|
||||
@@ -196,6 +182,9 @@ public class JavaFindUsagesHelper {
|
||||
FunctionalExpressionSearch.search(psiMethod, methodOptions.searchScope).forEach(new PsiElementProcessorAdapter<>(
|
||||
expression -> addResult(expression, options, processor)));
|
||||
}
|
||||
if (methodOptions.isImplicitToString) {
|
||||
ImplicitToStringSearch.search(psiMethod, methodOptions.searchScope).forEach(new PsiElementProcessorAdapter<>(ref -> addResult(ref, options, processor)));
|
||||
}
|
||||
}
|
||||
|
||||
if (element instanceof PomTarget) {
|
||||
|
||||
+7
-15
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.find.findUsages;
|
||||
|
||||
import com.intellij.find.FindBundle;
|
||||
@@ -31,6 +17,7 @@ public class JavaMethodFindUsagesOptions extends JavaFindUsagesOptions {
|
||||
public boolean isCheckDeepInheritance = true;
|
||||
public boolean isIncludeInherited;
|
||||
public boolean isIncludeOverloadUsages;
|
||||
public boolean isImplicitToString = true;
|
||||
|
||||
public JavaMethodFindUsagesOptions(@NotNull Project project) {
|
||||
super(project);
|
||||
@@ -54,6 +41,7 @@ public class JavaMethodFindUsagesOptions extends JavaFindUsagesOptions {
|
||||
if (isIncludeInherited != that.isIncludeInherited) return false;
|
||||
if (isIncludeOverloadUsages != that.isIncludeOverloadUsages) return false;
|
||||
if (isOverridingMethods != that.isOverridingMethods) return false;
|
||||
if (isImplicitToString != that.isImplicitToString) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -65,6 +53,7 @@ public class JavaMethodFindUsagesOptions extends JavaFindUsagesOptions {
|
||||
result = 31 * result + (isCheckDeepInheritance ? 1 : 0);
|
||||
result = 31 * result + (isIncludeInherited ? 1 : 0);
|
||||
result = 31 * result + (isIncludeOverloadUsages ? 1 : 0);
|
||||
result = 31 * result + (isImplicitToString ? 1 : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -80,6 +69,9 @@ public class JavaMethodFindUsagesOptions extends JavaFindUsagesOptions {
|
||||
if (isOverridingMethods) {
|
||||
strings.add(FindBundle.message("find.usages.panel.title.overriding.methods"));
|
||||
}
|
||||
if (isImplicitToString) {
|
||||
strings.add(FindBundle.message("find.usages.panel.title.implicit.to.string.calls"));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +1,10 @@
|
||||
/*
|
||||
* Copyright 2000-2009 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.
|
||||
*/
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.find.findUsages;
|
||||
|
||||
import com.intellij.find.FindBundle;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.search.ImplicitToStringSearcher;
|
||||
import com.intellij.ui.IdeBorderFactory;
|
||||
import com.intellij.ui.StateRestoringCheckBox;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -28,6 +15,7 @@ public class FindMethodUsagesDialog extends JavaFindUsagesDialog<JavaMethodFindU
|
||||
private StateRestoringCheckBox myCbUsages;
|
||||
private StateRestoringCheckBox myCbImplementingMethods;
|
||||
private StateRestoringCheckBox myCbOverridingMethods;
|
||||
private StateRestoringCheckBox myCbImplicitToString;
|
||||
private boolean myHasFindWhatPanel;
|
||||
|
||||
public FindMethodUsagesDialog(PsiElement element, Project project, FindUsagesOptions findUsagesOptions, boolean toShowInNewTab, boolean mustOpenInNewTab,
|
||||
@@ -53,6 +41,9 @@ public class FindMethodUsagesDialog extends JavaFindUsagesDialog<JavaMethodFindU
|
||||
if (isToChange(myCbImplementingMethods)) {
|
||||
options.isImplementingMethods = isSelected(myCbImplementingMethods);
|
||||
}
|
||||
if (isToChange(myCbImplicitToString)) {
|
||||
options.isImplicitToString = isSelected(myCbImplicitToString);
|
||||
}
|
||||
options.isCheckDeepInheritance = true;
|
||||
}
|
||||
|
||||
@@ -66,22 +57,33 @@ public class FindMethodUsagesDialog extends JavaFindUsagesDialog<JavaMethodFindU
|
||||
|
||||
PsiMethod method = (PsiMethod) getPsiElement();
|
||||
PsiClass aClass = method.getContainingClass();
|
||||
if (!method.isConstructor() &&
|
||||
!method.hasModifierProperty(PsiModifier.STATIC) &&
|
||||
!method.hasModifierProperty(PsiModifier.FINAL) &&
|
||||
!method.hasModifierProperty(PsiModifier.PRIVATE) &&
|
||||
aClass != null &&
|
||||
!(aClass instanceof PsiAnonymousClass) &&
|
||||
!aClass.hasModifierProperty(PsiModifier.FINAL)) {
|
||||
if (method.hasModifierProperty(PsiModifier.ABSTRACT)) {
|
||||
myCbImplementingMethods = addCheckboxToPanel(FindBundle.message("find.what.implementing.methods.checkbox"), getFindUsagesOptions().isImplementingMethods, findWhatPanel, true);
|
||||
} else {
|
||||
myCbOverridingMethods = addCheckboxToPanel(FindBundle.message("find.what.overriding.methods.checkbox"), getFindUsagesOptions().isOverridingMethods, findWhatPanel, true);
|
||||
}
|
||||
} else {
|
||||
if (method.isConstructor() ||
|
||||
method.hasModifierProperty(PsiModifier.STATIC) ||
|
||||
method.hasModifierProperty(PsiModifier.FINAL) ||
|
||||
method.hasModifierProperty(PsiModifier.PRIVATE) ||
|
||||
aClass == null ||
|
||||
aClass instanceof PsiAnonymousClass ||
|
||||
aClass.hasModifierProperty(PsiModifier.FINAL)) {
|
||||
myHasFindWhatPanel = false;
|
||||
return null;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (method.hasModifierProperty(PsiModifier.ABSTRACT)) {
|
||||
myCbImplementingMethods =
|
||||
addCheckboxToPanel(FindBundle.message("find.what.implementing.methods.checkbox"), getFindUsagesOptions().isImplementingMethods,
|
||||
findWhatPanel, true);
|
||||
}
|
||||
else {
|
||||
myCbOverridingMethods =
|
||||
addCheckboxToPanel(FindBundle.message("find.what.overriding.methods.checkbox"), getFindUsagesOptions().isOverridingMethods,
|
||||
findWhatPanel, true);
|
||||
}
|
||||
if (ImplicitToStringSearcher.isToStringMethod(method)) {
|
||||
myCbImplicitToString =
|
||||
addCheckboxToPanel(FindBundle.message("find.what.implicit.to.string.checkbox"), getFindUsagesOptions().isImplicitToString,
|
||||
findWhatPanel, true);
|
||||
}
|
||||
|
||||
myHasFindWhatPanel = true;
|
||||
return findWhatPanel;
|
||||
|
||||
@@ -106,8 +108,10 @@ public class FindMethodUsagesDialog extends JavaFindUsagesDialog<JavaMethodFindU
|
||||
if (!myHasFindWhatPanel) {
|
||||
setOKActionEnabled(true);
|
||||
} else {
|
||||
|
||||
boolean hasSelected = isSelected(myCbUsages) || isSelected(myCbImplementingMethods) || isSelected(myCbOverridingMethods);
|
||||
boolean hasSelected = isSelected(myCbUsages) ||
|
||||
isSelected(myCbImplementingMethods) ||
|
||||
isSelected(myCbOverridingMethods) ||
|
||||
isSelected(myCbImplicitToString);
|
||||
setOKActionEnabled(hasSelected);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.psi.impl.search;
|
||||
|
||||
import com.intellij.compiler.CompilerReferenceService;
|
||||
import com.intellij.openapi.application.QueryExecutorBase;
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.java.JavaBinaryPlusExpressionIndex;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.GlobalSearchScopeUtil;
|
||||
import com.intellij.psi.search.searches.ImplicitToStringSearch;
|
||||
import com.intellij.psi.util.MethodSignatureUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.indexing.FileBasedIndex;
|
||||
import gnu.trove.THashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class ImplicitToStringSearcher extends QueryExecutorBase<PsiExpression, ImplicitToStringSearch.SearchParameters> {
|
||||
private static final Logger LOG = Logger.getInstance(ImplicitToStringSearcher.class);
|
||||
|
||||
@Override
|
||||
public void processQuery(@NotNull ImplicitToStringSearch.SearchParameters parameters, @NotNull Processor<PsiExpression> consumer) {
|
||||
PsiMethod targetMethod = parameters.getTargetMethod();
|
||||
Project project = PsiUtilCore.getProjectInReadAction(targetMethod);
|
||||
if (project == null) return;
|
||||
PsiClass aClass = ReadAction.compute(() -> targetMethod.getContainingClass());
|
||||
if (aClass == null) return;
|
||||
DumbService dumbService = DumbService.getInstance(project);
|
||||
Map<VirtualFile, int[]> fileOffsets = new THashMap<>();
|
||||
dumbService.runReadActionInSmartMode(() -> {
|
||||
CompilerReferenceService compilerReferenceService = CompilerReferenceService.getInstance(project);
|
||||
GlobalSearchScope scopeWithoutToString = compilerReferenceService == null ? null : compilerReferenceService.getScopeWithoutImplicitToStringCodeReferences(aClass);
|
||||
GlobalSearchScope filter = GlobalSearchScopeUtil.toGlobalSearchScope(scopeWithoutToString == null
|
||||
? parameters.getSearchScope()
|
||||
: GlobalSearchScope.notScope(scopeWithoutToString).intersectWith(parameters.getSearchScope()), project);
|
||||
FileBasedIndex.getInstance().processValues(JavaBinaryPlusExpressionIndex.INDEX_ID, Boolean.TRUE, null,
|
||||
(file, value) -> {
|
||||
ProgressManager.checkCanceled();
|
||||
fileOffsets.put(file, value.getOffsets());
|
||||
return true;
|
||||
}, filter);
|
||||
|
||||
});
|
||||
|
||||
PsiManager psiManager = PsiManager.getInstance(project);
|
||||
for (Map.Entry<VirtualFile, int[]> entry : fileOffsets.entrySet()) {
|
||||
VirtualFile file = entry.getKey();
|
||||
int[] offsets = entry.getValue();
|
||||
ProgressManager.checkCanceled();
|
||||
if (!processFile(file, offsets, psiManager, targetMethod, consumer)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isToStringMethod(@NotNull PsiElement element) {
|
||||
if (!(element instanceof PsiMethod)) {
|
||||
return false;
|
||||
}
|
||||
PsiMethod method = (PsiMethod)element;
|
||||
if (!"toString".equals(method.getName())) {
|
||||
return false;
|
||||
}
|
||||
if (method.getParameters().length != 0) {
|
||||
return false;
|
||||
}
|
||||
PsiType returnType = method.getReturnType();
|
||||
return returnType != null && returnType.equalsToText(CommonClassNames.JAVA_LANG_STRING);
|
||||
}
|
||||
|
||||
private static boolean processFile(VirtualFile file,
|
||||
int[] offsets,
|
||||
PsiManager manager,
|
||||
PsiMethod targetMethod,
|
||||
Processor<PsiExpression> consumer) {
|
||||
return ReadAction.compute(() -> {
|
||||
PsiFile psiFile = ObjectUtils.notNull(manager.findFile(file));
|
||||
if (!(psiFile instanceof PsiJavaFile)) {
|
||||
LOG.error("Non-java file " + psiFile + "; " + file);
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int offset : offsets) {
|
||||
PsiJavaToken plusToken = PsiTreeUtil.findElementOfClassAtOffset(psiFile, offset, PsiJavaToken.class, false);
|
||||
if (plusToken == null) {
|
||||
LOG.error("plusToken shouldn't be null in " + psiFile + " at " + offset);
|
||||
continue;
|
||||
}
|
||||
PsiElement parent = plusToken.getParent();
|
||||
|
||||
if (parent instanceof PsiPolyadicExpression) {
|
||||
PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)parent;
|
||||
PsiType exprType = polyadicExpression.getType();
|
||||
if (exprType == null || !exprType.equalsToText(CommonClassNames.JAVA_LANG_STRING)) {
|
||||
continue;
|
||||
}
|
||||
PsiExpression[] operands = polyadicExpression.getOperands();
|
||||
for (PsiExpression operand : operands) {
|
||||
if (!processPolyadicExprOperand(operand, consumer, targetMethod)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG.error(parent + " expected to be polyadic expression");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private static boolean processPolyadicExprOperand(@NotNull PsiExpression expr,
|
||||
@NotNull Processor<PsiExpression> consumer,
|
||||
@NotNull PsiMethod targetMethod) {
|
||||
PsiType type = expr.getType();
|
||||
if (type instanceof PsiPrimitiveType) {
|
||||
type = ((PsiPrimitiveType)type).getBoxedType(expr);
|
||||
}
|
||||
PsiClass aClass = PsiUtil.resolveClassInClassTypeOnly(type);
|
||||
if (aClass != null && !CommonClassNames.JAVA_LANG_STRING.equals(aClass.getQualifiedName())) {
|
||||
PsiMethod implicitlyUsedMethod = aClass.findMethodBySignature(targetMethod, true);
|
||||
if (implicitlyUsedMethod != null && (targetMethod == implicitlyUsedMethod || MethodSignatureUtil.isSuperMethod(targetMethod, implicitlyUsedMethod))) {
|
||||
return consumer.process(expr);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static class MyImplicitToStringReference implements PsiReference {
|
||||
private final PsiElement myPlace;
|
||||
private final PsiMethod myTargetMethod;
|
||||
|
||||
private MyImplicitToStringReference(PsiElement place, PsiMethod method) {
|
||||
myPlace = place;
|
||||
myTargetMethod = method;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement getElement() {
|
||||
return myPlace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextRange getRangeInElement() {
|
||||
return new TextRange(0, myPlace.getTextLength());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiElement resolve() {
|
||||
return myTargetMethod;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getCanonicalText() {
|
||||
return myPlace.getText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReferenceTo(PsiElement element) {
|
||||
return element == myTargetMethod;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Object[] getVariants() {
|
||||
return ArrayUtil.EMPTY_OBJECT_ARRAY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSoft() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.psi.search.searches;
|
||||
|
||||
import com.intellij.psi.PsiExpression;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.search.SearchScope;
|
||||
import com.intellij.util.Query;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ImplicitToStringSearch extends ExtensibleQueryFactory<PsiExpression, ImplicitToStringSearch.SearchParameters> {
|
||||
public static final ImplicitToStringSearch INSTANCE = new ImplicitToStringSearch();
|
||||
|
||||
public static class SearchParameters {
|
||||
private final PsiMethod myTargetMethod;
|
||||
@NotNull
|
||||
private final SearchScope myScope;
|
||||
|
||||
public SearchParameters(@NotNull PsiMethod targetMethod, @NotNull SearchScope scope) {
|
||||
myTargetMethod = targetMethod;
|
||||
myScope = scope;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PsiMethod getTargetMethod() {
|
||||
return myTargetMethod;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public SearchScope getSearchScope() {
|
||||
return myScope;
|
||||
}
|
||||
}
|
||||
|
||||
public static Query<PsiExpression> search(@NotNull PsiMethod targetMethod, @NotNull SearchScope scope) {
|
||||
return INSTANCE.createUniqueResultsQuery(new SearchParameters(targetMethod, scope));
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@
|
||||
<extensionPoint qualifiedName="com.intellij.annotatedElementsSearch" interface="com.intellij.util.QueryExecutor"/>
|
||||
<extensionPoint qualifiedName="com.intellij.annotatedPackagesSearch" interface="com.intellij.util.QueryExecutor"/>
|
||||
<extensionPoint qualifiedName="com.intellij.functionalExpressionSearch" interface="com.intellij.util.QueryExecutor"/>
|
||||
<extensionPoint qualifiedName="com.intellij.implicitToStringSearch" interface="com.intellij.util.QueryExecutor"/>
|
||||
<extensionPoint qualifiedName="com.intellij.customPropertyScopeProvider" interface="com.intellij.psi.impl.search.CustomPropertyScopeProvider"/>
|
||||
</extensionPoints>
|
||||
|
||||
@@ -61,6 +62,7 @@
|
||||
serviceImplementation="com.intellij.psi.impl.search.HighlightingCaches"/>
|
||||
<projectService serviceInterface="com.intellij.psi.impl.file.impl.JavaFileManager"
|
||||
serviceImplementation="com.intellij.psi.impl.file.impl.JavaFileManagerImpl"/>
|
||||
<implicitToStringSearch implementation="com.intellij.psi.impl.search.ImplicitToStringSearcher"/>
|
||||
<functionalExpressionSearch implementation="com.intellij.psi.impl.search.JavaFunctionalExpressionSearcher"/>
|
||||
<definitionsScopedSearch implementation="com.intellij.codeInsight.navigation.ClassImplementationsSearch"/>
|
||||
<definitionsScopedSearch implementation="com.intellij.codeInsight.navigation.MethodImplementationsSearch"/>
|
||||
@@ -80,5 +82,6 @@
|
||||
<referencesSearch implementation="com.intellij.psi.impl.search.SPIReferencesSearcher"/>
|
||||
<referencesSearch implementation="com.intellij.psi.impl.search.ConstructorReferencesSearcher"/>
|
||||
<referencesSearch implementation="com.intellij.psi.impl.search.PsiAnnotationMethodReferencesSearcher"/>
|
||||
<fileBasedIndex implementation="com.intellij.psi.impl.java.JavaBinaryPlusExpressionIndex"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
@@ -37,6 +37,9 @@ public abstract class CompilerReferenceService extends AbstractProjectComponent
|
||||
@Nullable
|
||||
public abstract GlobalSearchScope getScopeWithoutCodeReferences(@NotNull PsiElement element);
|
||||
|
||||
@Nullable
|
||||
public abstract GlobalSearchScope getScopeWithoutImplicitToStringCodeReferences(@NotNull PsiElement aClass);
|
||||
|
||||
/**
|
||||
* @return a hierarchy of direct inheritors built on compilation time.
|
||||
* This hierarchy is restricted by searchFileType and searchScope.
|
||||
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.psi.impl.java;
|
||||
|
||||
import com.intellij.ide.highlighter.JavaFileType;
|
||||
import com.intellij.lang.LighterAST;
|
||||
import com.intellij.lang.LighterASTNode;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.impl.source.JavaFileElementType;
|
||||
import com.intellij.psi.impl.source.tree.ElementType;
|
||||
import com.intellij.psi.impl.source.tree.JavaElementType;
|
||||
import com.intellij.psi.impl.source.tree.LightTreeUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.indexing.*;
|
||||
import com.intellij.util.io.BooleanDataDescriptor;
|
||||
import com.intellij.util.io.DataExternalizer;
|
||||
import com.intellij.util.io.DataInputOutputUtil;
|
||||
import com.intellij.util.io.KeyDescriptor;
|
||||
import com.intellij.util.text.StringSearcher;
|
||||
import gnu.trove.THashMap;
|
||||
import gnu.trove.TIntArrayList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import static com.intellij.psi.impl.source.tree.JavaElementType.BINARY_EXPRESSION;
|
||||
import static com.intellij.psi.impl.source.tree.JavaElementType.POLYADIC_EXPRESSION;
|
||||
|
||||
public class JavaBinaryPlusExpressionIndex extends FileBasedIndexExtension<Boolean, JavaBinaryPlusExpressionIndex.PlusOffsets> implements PsiDependentIndex {
|
||||
public static final ID<Boolean, PlusOffsets> INDEX_ID = ID.create("java.binary.plus.expression");
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ID<Boolean, PlusOffsets> getName() {
|
||||
return INDEX_ID;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DataIndexer<Boolean, PlusOffsets, FileContent> getIndexer() {
|
||||
return inputData -> {
|
||||
CharSequence text = inputData.getContentAsText();
|
||||
int[] offsets = new StringSearcher("+", true, true).findAllOccurrences(text);
|
||||
if (offsets.length == 0) return Collections.emptyMap();
|
||||
|
||||
LighterAST tree = ((FileContentImpl)inputData).getLighterASTForPsiDependentIndex();
|
||||
TIntArrayList result = new TIntArrayList();
|
||||
for (int offset : offsets) {
|
||||
LighterASTNode leaf = LightTreeUtil.findLeafElementAt(tree, offset);
|
||||
LighterASTNode element = leaf == null ? null : tree.getParent(leaf);
|
||||
if (element == null) continue;
|
||||
|
||||
if ((element.getTokenType() == BINARY_EXPRESSION || element.getTokenType() == POLYADIC_EXPRESSION) && !isStringConcatenation(element, tree)) {
|
||||
result.add(offset);
|
||||
}
|
||||
}
|
||||
THashMap<Boolean, PlusOffsets> resultMap = ContainerUtil.newTroveMap();
|
||||
resultMap.put(Boolean.TRUE, new PlusOffsets(result.toNativeArray()));
|
||||
return resultMap;
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public KeyDescriptor<Boolean> getKeyDescriptor() {
|
||||
return BooleanDataDescriptor.INSTANCE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DataExternalizer<PlusOffsets> getValueExternalizer() {
|
||||
return new DataExternalizer<PlusOffsets>() {
|
||||
@Override
|
||||
public void save(@NotNull DataOutput out, PlusOffsets value) throws IOException {
|
||||
int[] offsets = value.getOffsets();
|
||||
DataInputOutputUtil.writeINT(out, offsets.length);
|
||||
for (int i : offsets) {
|
||||
DataInputOutputUtil.writeINT(out, i);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlusOffsets read(@NotNull DataInput in) throws IOException {
|
||||
int[] result = new int[DataInputOutputUtil.readINT(in)];
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
result[i] = DataInputOutputUtil.readINT(in);
|
||||
}
|
||||
return new PlusOffsets(result);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public FileBasedIndex.InputFilter getInputFilter() {
|
||||
return new DefaultFileTypeSpecificInputFilter(JavaFileType.INSTANCE) {
|
||||
@Override
|
||||
public boolean acceptInput(@NotNull VirtualFile file) {
|
||||
return super.acceptInput(file) && JavaFileElementType.isInSourceContent(file);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dependsOnFileContent() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static class PlusOffsets {
|
||||
private final int[] offsets;
|
||||
|
||||
public PlusOffsets(int[] offsets) {this.offsets = offsets;}
|
||||
|
||||
public int[] getOffsets() {
|
||||
return offsets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
PlusOffsets offsets1 = (PlusOffsets)o;
|
||||
|
||||
if (!Arrays.equals(offsets, offsets1.offsets)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(offsets);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isStringConcatenation(@NotNull LighterASTNode concatExpr, @NotNull LighterAST tree) {
|
||||
return LightTreeUtil
|
||||
.getChildrenOfType(tree, concatExpr, ElementType.EXPRESSION_BIT_SET)
|
||||
.stream()
|
||||
.allMatch(e -> e.getTokenType() == JavaElementType.LITERAL_EXPRESSION);
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
class A {
|
||||
void m(FooImpl f) {
|
||||
String s = "f = " + f.toString();
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
class B {
|
||||
void m(FooImpl f) {
|
||||
String s = "f = " + f;
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
class FooImpl extends Foo {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FooImpl instance";
|
||||
}
|
||||
}
|
||||
|
||||
class Foo {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Foo instance";
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
public class Foo {
|
||||
public void bar(long l) {
|
||||
System.out.println("xxx " + l + " yyy");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
class Foo {
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(new Foo() + "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Foo";
|
||||
}
|
||||
}
|
||||
+23
-15
@@ -1,24 +1,11 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.
|
||||
*/
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.java.compiler;
|
||||
|
||||
import com.intellij.JavaTestUtil;
|
||||
import com.intellij.codeInsight.daemon.DaemonAnalyzerTestCase;
|
||||
import com.intellij.compiler.CompilerConfiguration;
|
||||
import com.intellij.compiler.CompilerReferenceService;
|
||||
import com.intellij.find.findUsages.JavaFindUsagesHandlerFactory;
|
||||
import com.intellij.lang.injection.InjectedLanguageManager;
|
||||
import com.intellij.openapi.compiler.options.ExcludeEntryDescription;
|
||||
import com.intellij.openapi.compiler.options.ExcludesConfiguration;
|
||||
@@ -172,6 +159,17 @@ public class CompilerReferencesFindUsagesTest extends DaemonAnalyzerTestCase {
|
||||
Arrays.stream(findClass("Foo").findMethodsByName("bar", false)).forEach((m) -> assertSize(2, searchReferences(m)));
|
||||
}
|
||||
|
||||
public void testImplicitToStringSearch() {
|
||||
configureByFiles(getName(), getName() + "/Foo.java", getName() + "/A.java", getName() + "/B.java");
|
||||
Arrays.stream(findClass("FooImpl").findMethodsByName("toString", false)).forEach((m) -> assertEquals(2, searchUsages(m)));
|
||||
Arrays.stream(findClass("Foo").findMethodsByName("toString", false)).forEach((m) -> assertEquals(2, searchUsages(m)));
|
||||
Arrays.stream(myJavaFacade.findClass(CommonClassNames.JAVA_LANG_OBJECT).findMethodsByName("toString", false)).forEach((m) -> assertEquals(2, searchUsages(m)));
|
||||
myCompilerTester.rebuild();
|
||||
Arrays.stream(findClass("FooImpl").findMethodsByName("toString", false)).forEach((m) -> assertEquals(2, searchUsages(m)));
|
||||
Arrays.stream(findClass("Foo").findMethodsByName("toString", false)).forEach((m) -> assertEquals(2, searchUsages(m)));
|
||||
Arrays.stream(myJavaFacade.findClass(CommonClassNames.JAVA_LANG_OBJECT).findMethodsByName("toString", false)).forEach((m) -> assertEquals(2, searchUsages(m)));
|
||||
}
|
||||
|
||||
private void doTestRunnableFindUsagesWithExcludesConfiguration(@NotNull Consumer<ExcludesConfiguration> excludesConfigurationPatcher,
|
||||
int expectedUsagesCount,
|
||||
String... testFiles) {
|
||||
@@ -187,6 +185,16 @@ public class CompilerReferencesFindUsagesTest extends DaemonAnalyzerTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
private int searchUsages(@NotNull PsiMethod method) {
|
||||
JavaFindUsagesHandlerFactory factory = JavaFindUsagesHandlerFactory.getInstance(getProject());
|
||||
int[] count = {0};
|
||||
factory.createFindUsagesHandler(method, false).processElementUsages(method, info -> {
|
||||
count[0]++;
|
||||
return true;
|
||||
}, factory.getFindMethodOptions());
|
||||
return count[0];
|
||||
}
|
||||
|
||||
private Collection<PsiReference> searchReferences(@NotNull PsiElement element) {
|
||||
if (element instanceof PsiMethod) {
|
||||
return MethodReferencesSearch.search((PsiMethod)element, GlobalSearchScope.projectScope(getProject()), false).findAll();
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.java.psi.impl.search
|
||||
|
||||
import com.intellij.openapi.fileTypes.StdFileTypes
|
||||
import com.intellij.psi.impl.java.JavaBinaryPlusExpressionIndex
|
||||
import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase
|
||||
import com.intellij.util.indexing.FileContentImpl
|
||||
import com.intellij.util.indexing.IndexingDataKeys
|
||||
import org.intellij.lang.annotations.Language
|
||||
|
||||
class JavaBinaryPlusExpressionIndexTest : LightPlatformCodeInsightFixtureTestCase() {
|
||||
fun testIndex() {
|
||||
@Language("JAVA")
|
||||
val file = myFixture.configureByText(StdFileTypes.JAVA, """
|
||||
package org.some;
|
||||
|
||||
class Xyz {
|
||||
|
||||
void someMethod(Long o, String o2) {
|
||||
String s = "qwe" + "asd";
|
||||
String s1 = "qwe" + o;
|
||||
String s2 = "qwe" + o2 + "xxx";
|
||||
}
|
||||
}
|
||||
""").virtualFile
|
||||
val content = FileContentImpl.createByFile(file)
|
||||
content.putUserData(IndexingDataKeys.PROJECT, project)
|
||||
val data = JavaBinaryPlusExpressionIndex().indexer.map(content).entries.first().value.offsets!!
|
||||
|
||||
assertEquals(3, data.size)
|
||||
assertEquals(190, data[0])
|
||||
assertEquals(231, data[1])
|
||||
assertEquals(236, data[2])
|
||||
}
|
||||
}
|
||||
@@ -173,6 +173,20 @@ public class FindUsagesTest extends PsiTestCase{
|
||||
}
|
||||
}
|
||||
|
||||
public void testImplicitToString() {
|
||||
PsiClass aClass = myJavaFacade.findClass("Foo");
|
||||
assertNotNull(aClass);
|
||||
PsiMethod toString = assertOneElement(aClass.findMethodsByName("toString", false));
|
||||
|
||||
JavaFindUsagesHandlerFactory factory = JavaFindUsagesHandlerFactory.getInstance(myProject);
|
||||
int[] count = {0};
|
||||
factory.createFindUsagesHandler(toString, false).processElementUsages(toString, info -> {
|
||||
count[0]++;
|
||||
return true;
|
||||
}, factory.getFindMethodOptions());
|
||||
assertEquals(1, count[0]);
|
||||
}
|
||||
|
||||
public static void doTest(PsiElement element, String[] fileNames, int[] starts, int[] ends) {
|
||||
final ArrayList<PsiFile> filesList = new ArrayList<>();
|
||||
final IntArrayList startsList = new IntArrayList();
|
||||
|
||||
+10
-4
@@ -1,12 +1,11 @@
|
||||
// Copyright 2000-2017 JetBrains s.r.o.
|
||||
// Use of this source code is governed by the Apache 2.0 license that can be
|
||||
// found in the LICENSE file.
|
||||
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.jps.javac.ast;
|
||||
|
||||
import com.intellij.util.Consumer;
|
||||
import com.sun.source.tree.*;
|
||||
import com.sun.source.util.*;
|
||||
import com.sun.tools.javac.util.ClientCodeException;
|
||||
import gnu.trove.THashSet;
|
||||
import gnu.trove.TObjectIntHashMap;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.javac.ast.api.*;
|
||||
@@ -216,7 +215,8 @@ final class JavacReferenceCollectorListener implements TaskListener {
|
||||
createReferenceHolder(),
|
||||
myDivideImportRefs ? createReferenceHolder() : EMPTY_T_OBJ_INT_MAP,
|
||||
new ArrayList<JavacTypeCast>(),
|
||||
createDefinitionHolder());
|
||||
createDefinitionHolder(),
|
||||
new THashSet<JavacRef>());
|
||||
myTreeHelper = new JavacTreeHelper(unitTree, myTreeUtility);
|
||||
}
|
||||
|
||||
@@ -228,6 +228,12 @@ final class JavacReferenceCollectorListener implements TaskListener {
|
||||
myFileData.getDefs().add(def);
|
||||
}
|
||||
|
||||
void sinkImplicitToString(@Nullable JavacRef ref) {
|
||||
if (ref != null) {
|
||||
myFileData.getImplicitToStringRefs().add(ref);
|
||||
}
|
||||
}
|
||||
|
||||
public void sinkTypeCast(JavacTypeCast typeCast) {
|
||||
myFileData.getCasts().add(typeCast);
|
||||
}
|
||||
|
||||
@@ -4,16 +4,15 @@ package org.jetbrains.jps.javac.ast;
|
||||
import com.intellij.util.containers.Stack;
|
||||
import com.sun.source.tree.*;
|
||||
import com.sun.source.util.TreeScanner;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.jps.javac.ast.api.JavacDef;
|
||||
import org.jetbrains.jps.javac.ast.api.JavacNameTable;
|
||||
import org.jetbrains.jps.javac.ast.api.JavacRef;
|
||||
import org.jetbrains.jps.javac.ast.api.JavacTypeCast;
|
||||
|
||||
import javax.lang.model.element.*;
|
||||
import javax.lang.model.type.ArrayType;
|
||||
import javax.lang.model.type.DeclaredType;
|
||||
import javax.lang.model.type.TypeKind;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
import javax.lang.model.type.*;
|
||||
import javax.lang.model.util.Types;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -116,6 +115,25 @@ class JavacTreeRefScanner extends TreeScanner<Tree, JavacReferenceCollectorListe
|
||||
return super.visitMethod(node, refCollector);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tree visitBinary(BinaryTree node, JavacReferenceCollectorListener.ReferenceCollector collector) {
|
||||
Tree.Kind kind = node.getKind();
|
||||
if (kind == Tree.Kind.PLUS) {
|
||||
ExpressionTree lOp = node.getLeftOperand();
|
||||
ExpressionTree rOp = node.getRightOperand();
|
||||
Set<TypeElement> typeElements = extractImplicitToStringCalls(lOp, rOp, collector);
|
||||
if (typeElements != null) {
|
||||
for (TypeElement element : typeElements) {
|
||||
JavacRef.JavacElementRefBase ref = collector.asJavacRef(element);
|
||||
if (ref != null) {
|
||||
collector.sinkImplicitToString(ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.visitBinary(node, collector);
|
||||
}
|
||||
|
||||
private void processMemberDefinition(JavacReferenceCollectorListener.ReferenceCollector refCollector,
|
||||
JavacRef.JavacElementRefBase ref,
|
||||
Element element,
|
||||
@@ -164,7 +182,6 @@ class JavacTreeRefScanner extends TreeScanner<Tree, JavacReferenceCollectorListe
|
||||
|
||||
private final Stack<TypeElement> myCurrentEnclosingElement = new Stack<TypeElement>(1);
|
||||
private final Stack<Long> myCurrentEnclosingElementOffset = new Stack<Long>(1);
|
||||
private final Stack<NewClassTree> myCurrentAnonymousTree = new Stack<NewClassTree>(1);
|
||||
|
||||
@Override
|
||||
public Tree visitClass(ClassTree node, JavacReferenceCollectorListener.ReferenceCollector refCollector) {
|
||||
@@ -339,4 +356,57 @@ class JavacTreeRefScanner extends TreeScanner<Tree, JavacReferenceCollectorListe
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Set<TypeElement> extractImplicitToStringCalls(Tree lOp,
|
||||
Tree rOp,
|
||||
JavacReferenceCollectorListener.ReferenceCollector collector) {
|
||||
TypeMirror lTypeMirror = collector.getType(lOp);
|
||||
if (lTypeMirror == null) return null;
|
||||
TypeElement lType = asTypeElement(lTypeMirror, collector.getTypeUtility());
|
||||
if (lType == null) return null;
|
||||
TypeMirror rTypeMirror = collector.getType(rOp);
|
||||
if (rTypeMirror == null) return null;
|
||||
TypeElement rType = asTypeElement(rTypeMirror, collector.getTypeUtility());
|
||||
if (rType == null) return null;
|
||||
|
||||
if (isToStringImplicitCall(lType, rType, collector)) {
|
||||
Set<TypeElement> result = new THashSet<TypeElement>();
|
||||
visitTypeHierarchy(rType, result, collector.getTypeUtility());
|
||||
return result;
|
||||
}
|
||||
if (isToStringImplicitCall(rType, lType, collector)) {
|
||||
Set<TypeElement> result = new THashSet<TypeElement>();
|
||||
visitTypeHierarchy(lType, result, collector.getTypeUtility());
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static TypeElement asTypeElement(TypeMirror typeMirror, Types typeUtility) {
|
||||
if (typeMirror instanceof PrimitiveType) {
|
||||
return typeUtility.boxedClass((PrimitiveType)typeMirror);
|
||||
}
|
||||
Element element = typeUtility.asElement(typeMirror);
|
||||
return element instanceof TypeElement ? (TypeElement)element : null;
|
||||
}
|
||||
|
||||
private static boolean isToStringImplicitCall(TypeElement strElement, TypeElement element, JavacReferenceCollectorListener.ReferenceCollector collector) {
|
||||
TypeElement stringEthalone = collector.getNameTable().getStringElement();
|
||||
return strElement == stringEthalone && element != stringEthalone;
|
||||
}
|
||||
|
||||
private static void visitTypeHierarchy(TypeElement element, Set<TypeElement> collector, Types typeUtility) {
|
||||
if (collector.add(element)) {
|
||||
TypeMirror superclass = element.getSuperclass();
|
||||
Element superClass = typeUtility.asElement(superclass);
|
||||
if (superClass instanceof TypeElement) {
|
||||
visitTypeHierarchy((TypeElement)superClass, collector, typeUtility);
|
||||
}
|
||||
for (TypeMirror mirror : element.getInterfaces()) {
|
||||
if (mirror instanceof TypeElement) {
|
||||
visitTypeHierarchy((TypeElement)mirror, collector, typeUtility);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +1,10 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.
|
||||
*/
|
||||
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.jps.javac.ast.api;
|
||||
|
||||
import com.intellij.openapi.util.ThrowableComputable;
|
||||
import com.intellij.openapi.util.io.DataInputOutputUtilRt;
|
||||
import com.intellij.util.ThrowableConsumer;
|
||||
import gnu.trove.THashSet;
|
||||
import gnu.trove.TObjectIntHashMap;
|
||||
import gnu.trove.TObjectIntProcedure;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -37,17 +24,20 @@ public class JavacFileData {
|
||||
private final TObjectIntHashMap<JavacRef> myImportRefs;
|
||||
private final List<JavacTypeCast> myCasts;
|
||||
private final List<JavacDef> myDefs;
|
||||
private final Set<JavacRef> myImplicitRefs;
|
||||
|
||||
public JavacFileData(@NotNull String path,
|
||||
@NotNull TObjectIntHashMap<JavacRef> refs,
|
||||
@NotNull TObjectIntHashMap<JavacRef> importRefs,
|
||||
@NotNull List<JavacTypeCast> casts,
|
||||
@NotNull List<JavacDef> defs) {
|
||||
@NotNull List<JavacDef> defs,
|
||||
@NotNull Set<JavacRef> implicitRefs) {
|
||||
myFilePath = path;
|
||||
myRefs = refs;
|
||||
myImportRefs = importRefs;
|
||||
myCasts = casts;
|
||||
myDefs = defs;
|
||||
myImplicitRefs = implicitRefs;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -55,6 +45,11 @@ public class JavacFileData {
|
||||
return myFilePath;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Set<JavacRef> getImplicitToStringRefs() {
|
||||
return myImplicitRefs;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public TObjectIntHashMap<JavacRef> getRefs() {
|
||||
return myRefs;
|
||||
@@ -85,6 +80,7 @@ public class JavacFileData {
|
||||
saveRefs(stream, getImportRefs());
|
||||
saveCasts(stream, getCasts());
|
||||
saveDefs(stream, getDefs());
|
||||
saveImplicitToString(stream, getImplicitToStringRefs());
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
@@ -101,7 +97,8 @@ public class JavacFileData {
|
||||
readRefs(in),
|
||||
readRefs(in),
|
||||
readCasts(in),
|
||||
readDefs(in));
|
||||
readDefs(in),
|
||||
readImplicitToString(in));
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
@@ -276,4 +273,21 @@ public class JavacFileData {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Set<JavacRef> readImplicitToString(@NotNull DataInputStream in) throws IOException {
|
||||
int size = DataInputOutputUtilRt.readINT(in);
|
||||
THashSet<JavacRef> result = new THashSet<JavacRef>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
result.add(readJavacRef(in));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void saveImplicitToString(@NotNull DataOutputStream out, @NotNull Set<JavacRef> refs) throws IOException {
|
||||
DataInputOutputUtilRt.writeINT(out, refs.size());
|
||||
for (JavacRef ref : refs) {
|
||||
writeJavacRef(out, ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.
|
||||
*/
|
||||
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.jps.javac.ast.api;
|
||||
|
||||
import com.intellij.util.containers.SLRUCache;
|
||||
@@ -32,6 +18,7 @@ public class JavacNameTable {
|
||||
private TypeElement myStreamElement;
|
||||
private TypeElement myIteratorElement;
|
||||
private TypeElement myIterableElement;
|
||||
private TypeElement myStringElement;
|
||||
|
||||
public JavacNameTable(Elements elements) {
|
||||
myParsedNameCache = new SLRUCache<Name, String>(1000, 1000) {
|
||||
@@ -91,4 +78,12 @@ public class JavacNameTable {
|
||||
}
|
||||
return myIterableElement;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public TypeElement getStringElement() {
|
||||
if (myStringElement == null) {
|
||||
myStringElement = myElements.getTypeElement("java.lang.String");
|
||||
}
|
||||
return myStringElement;
|
||||
}
|
||||
}
|
||||
|
||||
+9
-18
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.
|
||||
*/
|
||||
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.jps.backwardRefs;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
@@ -38,6 +24,7 @@ public class BackwardReferenceIndexUtil {
|
||||
TObjectIntHashMap<? extends JavacRef> refs,
|
||||
Collection<JavacDef> defs,
|
||||
Collection<JavacTypeCast> casts,
|
||||
Collection<JavacRef> implicitToString,
|
||||
final BackwardReferenceIndexWriter writer) {
|
||||
|
||||
try {
|
||||
@@ -47,8 +34,8 @@ public class BackwardReferenceIndexUtil {
|
||||
Map<LightRef, Void> definitions = new HashMap<>(defs.size());
|
||||
Map<LightRef, Collection<LightRef>> backwardHierarchyMap = new HashMap<>();
|
||||
Map<SignatureData, Collection<LightRef>> signatureData = new THashMap<>();
|
||||
THashMap<LightRef, Collection<LightRef>> castMap = new THashMap<>();
|
||||
|
||||
Map<LightRef, Collection<LightRef>> castMap = new THashMap<>();
|
||||
Map<LightRef, Void> implicitToStringMap = new THashMap<>();
|
||||
|
||||
final AnonymousClassEnumerator anonymousClassEnumerator = new AnonymousClassEnumerator();
|
||||
|
||||
@@ -124,7 +111,11 @@ public class BackwardReferenceIndexUtil {
|
||||
castMap.computeIfAbsent(enumeratedCastType, t -> new SmartList<>()).add(enumeratedOperandType);
|
||||
}
|
||||
|
||||
writer.writeData(fileId, new CompiledFileData(backwardHierarchyMap, castMap, convertedRefs, definitions, signatureData));
|
||||
for (JavacRef ref : implicitToString) {
|
||||
implicitToStringMap.put(writer.asClassUsage(ref), null);
|
||||
}
|
||||
|
||||
writer.writeData(fileId, new CompiledFileData(backwardHierarchyMap, castMap, convertedRefs, definitions, signatureData, implicitToStringMap));
|
||||
}
|
||||
catch (IOException e) {
|
||||
writer.setRebuildCause(e);
|
||||
|
||||
+5
-18
@@ -1,25 +1,11 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.
|
||||
*/
|
||||
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.jps.backwardRefs;
|
||||
|
||||
import gnu.trove.TObjectIntHashMap;
|
||||
import org.jetbrains.jps.javac.ast.api.JavacTypeCast;
|
||||
import org.jetbrains.jps.javac.ast.api.JavacDef;
|
||||
import org.jetbrains.jps.javac.ast.api.JavacFileReferencesRegistrar;
|
||||
import org.jetbrains.jps.javac.ast.api.JavacRef;
|
||||
import org.jetbrains.jps.javac.ast.api.JavacTypeCast;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@@ -45,7 +31,8 @@ public class BackwardReferenceRegistrar implements JavacFileReferencesRegistrar
|
||||
public void registerFile(String filePath,
|
||||
TObjectIntHashMap<JavacRef> refs,
|
||||
Collection<JavacDef> defs,
|
||||
Collection<JavacTypeCast> casts) {
|
||||
BackwardReferenceIndexUtil.registerFile(filePath, refs, defs, casts, myWriter);
|
||||
Collection<JavacTypeCast> casts,
|
||||
Collection<JavacRef> implicitToString) {
|
||||
BackwardReferenceIndexUtil.registerFile(filePath, refs, defs, casts, implicitToString, myWriter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.
|
||||
*/
|
||||
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.jps.backwardRefs.index;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -28,17 +14,20 @@ public class CompiledFileData {
|
||||
private final Map<LightRef, Integer> myReferences;
|
||||
private final Map<LightRef, Void> myDefinitions;
|
||||
private final Map<SignatureData, Collection<LightRef>> mySignatureData;
|
||||
private final Map<LightRef, Void> myImplicitToString;
|
||||
|
||||
public CompiledFileData(@NotNull Map<LightRef, Collection<LightRef>> backwardHierarchyMap,
|
||||
@NotNull Map<LightRef, Collection<LightRef>> casts,
|
||||
@NotNull Map<LightRef, Integer> references,
|
||||
@NotNull Map<LightRef, Void> definitions,
|
||||
@NotNull Map<SignatureData, Collection<LightRef>> signatureData) {
|
||||
@NotNull Map<SignatureData, Collection<LightRef>> signatureData,
|
||||
@NotNull Map<LightRef, Void> implicitToString) {
|
||||
myBackwardHierarchyMap = backwardHierarchyMap;
|
||||
myCasts = casts;
|
||||
myReferences = references;
|
||||
myDefinitions = definitions;
|
||||
mySignatureData = signatureData;
|
||||
myImplicitToString = implicitToString;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -65,4 +54,9 @@ public class CompiledFileData {
|
||||
public Map<LightRef, Collection<LightRef>> getCasts() {
|
||||
return myCasts;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Map<LightRef, Void> getImplicitToString() {
|
||||
return myImplicitToString;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.
|
||||
*/
|
||||
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.jps.backwardRefs.index;
|
||||
|
||||
import com.intellij.openapi.util.io.DataInputOutputUtilRt;
|
||||
@@ -44,13 +30,48 @@ public class CompilerIndices {
|
||||
public final static IndexId<LightRef, Void> BACK_CLASS_DEF = IndexId.create("back.class.def");
|
||||
public final static IndexId<SignatureData, Collection<LightRef>> BACK_MEMBER_SIGN = IndexId.create("back.member.sign");
|
||||
public final static IndexId<LightRef, Collection<LightRef>> BACK_CAST = IndexId.create("back.cast");
|
||||
public final static IndexId<LightRef, Void> IMPLICIT_TO_STRING = IndexId.create("implicit.to.string");
|
||||
|
||||
public static List<IndexExtension<?, ?, CompiledFileData>> getIndices() {
|
||||
return Arrays.asList(createBackwardClassDefinitionExtension(),
|
||||
createBackwardUsagesExtension(),
|
||||
createBackwardHierarchyExtension(),
|
||||
createBackwardSignatureExtension(),
|
||||
createBackwardCastExtension());
|
||||
createBackwardCastExtension(),
|
||||
createImplicitToStringExtension());
|
||||
}
|
||||
|
||||
private static IndexExtension<LightRef, Void, CompiledFileData> createImplicitToStringExtension() {
|
||||
return new IndexExtension<LightRef, Void, CompiledFileData>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public IndexId<LightRef, Void> getName() {
|
||||
return IMPLICIT_TO_STRING;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DataIndexer<LightRef, Void, CompiledFileData> getIndexer() {
|
||||
return CompiledFileData::getImplicitToString;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public KeyDescriptor<LightRef> getKeyDescriptor() {
|
||||
return LightRefDescriptor.INSTANCE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DataExternalizer<Void> getValueExternalizer() {
|
||||
return VoidDataExternalizer.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static IndexExtension<LightRef, Collection<LightRef>, CompiledFileData> createBackwardCastExtension() {
|
||||
|
||||
+2
-16
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.
|
||||
*/
|
||||
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.jps.javac.ast;
|
||||
|
||||
import com.intellij.util.Consumer;
|
||||
@@ -78,7 +64,7 @@ public class InProcessRefCollectorCompilerToolExtension extends AbstractRefColle
|
||||
public void consume(JavacFileData data) {
|
||||
for (JavacFileReferencesRegistrar registrar : myRegistrars) {
|
||||
if (registrar.isEnabled()) {
|
||||
registrar.registerFile(data.getFilePath(), registrar.onlyImports() ? data.getImportRefs() : data.getRefs(), data.getDefs(), data.getCasts());
|
||||
registrar.registerFile(data.getFilePath(), registrar.onlyImports() ? data.getImportRefs() : data.getRefs(), data.getDefs(), data.getCasts(), data.getImplicitToStringRefs());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-16
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.
|
||||
*/
|
||||
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.jps.javac.ast.api;
|
||||
|
||||
import gnu.trove.TObjectIntHashMap;
|
||||
@@ -29,5 +15,6 @@ public interface JavacFileReferencesRegistrar {
|
||||
void registerFile(String filePath,
|
||||
TObjectIntHashMap<JavacRef> refs,
|
||||
Collection<JavacDef> defs,
|
||||
Collection<JavacTypeCast> casts);
|
||||
Collection<JavacTypeCast> casts,
|
||||
Collection<JavacRef> implicitToString);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
class Foo {
|
||||
void m(Object o) {
|
||||
System.out.println("obj = " + o);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
Backward Hierarchy:
|
||||
java.lang.Object -> Foo
|
||||
|
||||
Backward References:
|
||||
Foo in Foo occurrences = 1
|
||||
Foo.m(1) in Foo occurrences = 1
|
||||
java.io.PrintStream.println(1) in Foo occurrences = 1
|
||||
java.lang.Object in Foo occurrences = 1
|
||||
java.lang.System in Foo occurrences = 1
|
||||
java.lang.System.out in Foo occurrences = 1
|
||||
|
||||
Class Definitions:
|
||||
Foo in Foo
|
||||
|
||||
Members Signatures:
|
||||
|
||||
|
||||
Implicit toString():
|
||||
java.lang.Object in Foo
|
||||
@@ -0,0 +1,15 @@
|
||||
class Foo {
|
||||
|
||||
}
|
||||
|
||||
class FooEx extends Foo {
|
||||
|
||||
}
|
||||
|
||||
class FooExEx extends FooEx {
|
||||
|
||||
public void m(FooExEx f) {
|
||||
System.out.println(f + " <--- f value");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
Backward Hierarchy:
|
||||
Foo -> FooEx
|
||||
FooEx -> FooExEx
|
||||
java.lang.Object -> Foo
|
||||
|
||||
Backward References:
|
||||
Foo in Foo occurrences = 2
|
||||
FooEx in Foo occurrences = 2
|
||||
FooExEx in Foo occurrences = 2
|
||||
FooExEx.m(1) in Foo occurrences = 1
|
||||
java.io.PrintStream.println(1) in Foo occurrences = 1
|
||||
java.lang.System in Foo occurrences = 1
|
||||
java.lang.System.out in Foo occurrences = 1
|
||||
|
||||
Class Definitions:
|
||||
Foo in Foo
|
||||
FooEx in Foo
|
||||
FooExEx in Foo
|
||||
|
||||
Members Signatures:
|
||||
|
||||
|
||||
Implicit toString():
|
||||
Foo in Foo
|
||||
FooEx in Foo
|
||||
FooExEx in Foo
|
||||
java.lang.Object in Foo
|
||||
@@ -0,0 +1,5 @@
|
||||
class A {
|
||||
void m(Long value) {
|
||||
System.out.println("value = " + value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
Backward Hierarchy:
|
||||
java.lang.Object -> A
|
||||
|
||||
Backward References:
|
||||
A in Foo occurrences = 1
|
||||
A.m(1) in Foo occurrences = 1
|
||||
java.io.PrintStream.println(1) in Foo occurrences = 1
|
||||
java.lang.Long in Foo occurrences = 1
|
||||
java.lang.System in Foo occurrences = 1
|
||||
java.lang.System.out in Foo occurrences = 1
|
||||
|
||||
Class Definitions:
|
||||
A in Foo
|
||||
|
||||
Members Signatures:
|
||||
|
||||
|
||||
Implicit toString():
|
||||
java.lang.Long in Foo
|
||||
java.lang.Number in Foo
|
||||
java.lang.Object in Foo
|
||||
@@ -0,0 +1,10 @@
|
||||
class A {
|
||||
void m(boolean b, char c, int i, long l, float f, double d) {
|
||||
System.out.println(" value " + b + " !! ");
|
||||
System.out.println(" value " + c);
|
||||
System.out.println(" value " + i + " !! ");
|
||||
System.out.println(" value " + l);
|
||||
System.out.println(" value " + f + " !! ");
|
||||
System.out.println(" value " + d);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
Backward Hierarchy:
|
||||
java.lang.Object -> A
|
||||
|
||||
Backward References:
|
||||
A in Foo occurrences = 1
|
||||
A.m(6) in Foo occurrences = 1
|
||||
java.io.PrintStream.println(1) in Foo occurrences = 6
|
||||
java.lang.System in Foo occurrences = 6
|
||||
java.lang.System.out in Foo occurrences = 6
|
||||
|
||||
Class Definitions:
|
||||
A in Foo
|
||||
|
||||
Members Signatures:
|
||||
|
||||
|
||||
Implicit toString():
|
||||
java.lang.Boolean in Foo
|
||||
java.lang.Character in Foo
|
||||
java.lang.Double in Foo
|
||||
java.lang.Float in Foo
|
||||
java.lang.Integer in Foo
|
||||
java.lang.Long in Foo
|
||||
java.lang.Number in Foo
|
||||
java.lang.Object in Foo
|
||||
@@ -183,5 +183,21 @@ class ReferenceIndexTest : ReferenceIndexTestBase() {
|
||||
fun testNestedAnonymouses() {
|
||||
assertIndexOnRebuild("Anonymouses.java", "Classes.java")
|
||||
}
|
||||
|
||||
fun testImplicitToString() {
|
||||
assertIndexOnRebuild("Foo.java")
|
||||
}
|
||||
|
||||
fun testImplicitToStringPrimitives() {
|
||||
assertIndexOnRebuild("Foo.java")
|
||||
}
|
||||
|
||||
fun testImplicitToStringLongObject() {
|
||||
assertIndexOnRebuild("Foo.java")
|
||||
}
|
||||
|
||||
fun testImplicitToStringHierarchy() {
|
||||
assertIndexOnRebuild("Foo.java")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.
|
||||
*/
|
||||
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.references
|
||||
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
@@ -179,6 +165,29 @@ abstract class ReferenceIndexTestBase : JpsBuildTestCase() {
|
||||
result.append(typeCasts.joinToString(separator = "\n"))
|
||||
}
|
||||
|
||||
val implicitToString = mutableListOf<String>()
|
||||
storage(index, CompilerIndices.IMPLICIT_TO_STRING).processKeys {type ->
|
||||
val callPlaceFiles = mutableListOf<String>()
|
||||
val valueIt = index[CompilerIndices.IMPLICIT_TO_STRING].getData(type).valueIterator
|
||||
while (valueIt.hasNext()) {
|
||||
valueIt.next()
|
||||
val files = valueIt.inputIdsIterator
|
||||
while (files.hasNext()) {
|
||||
callPlaceFiles.add(files.next().asFileName(fileEnumerator))
|
||||
}
|
||||
}
|
||||
if (!callPlaceFiles.isEmpty()) {
|
||||
callPlaceFiles.sort()
|
||||
implicitToString.add(type.asText(nameEnumerator) + " in " + callPlaceFiles.joinToString(separator = " "))
|
||||
}
|
||||
true
|
||||
}
|
||||
if (implicitToString.isNotEmpty()) {
|
||||
result.append("\n\nImplicit toString():\n")
|
||||
implicitToString.sort()
|
||||
result.append(implicitToString.joinToString(separator = "\n"))
|
||||
}
|
||||
|
||||
return result.toString()
|
||||
}
|
||||
finally {
|
||||
|
||||
@@ -19,6 +19,7 @@ find.what.derived.interfaces.checkbox=&Derived interfaces
|
||||
find.what.derived.classes.checkbox=&Derived classes
|
||||
find.what.implementing.methods.checkbox=&Implementing methods
|
||||
find.what.overriding.methods.checkbox=Over&riding methods
|
||||
find.what.implicit.to.string.checkbox=I&mplicit calls
|
||||
find.what.usages.of.classes.and.interfaces=Usages of &classes and interfaces
|
||||
|
||||
|
||||
@@ -60,6 +61,7 @@ find.usages.panel.title.derived.interfaces=Derived Interfaces
|
||||
find.usages.panel.title.implementing.classes=Implementing Classes
|
||||
find.usages.panel.title.implementing.methods=Implementing Methods
|
||||
find.usages.panel.title.overriding.methods=Overriding Methods
|
||||
find.usages.panel.title.implicit.to.string.calls=Implicit Calls
|
||||
find.usages.of.element_type.element_name.not.found.message=Usages of {0} {1} not found
|
||||
find.searching.for.references.to.class.progress=Searching for references to class {0}...
|
||||
find.usage.view.no.usages.text=No usages found
|
||||
|
||||
Reference in New Issue
Block a user