register Java fields referenced from injected fragments as read/written

This commit is contained in:
Alexey Kudravtsev
2016-05-24 15:23:25 +03:00
parent 9728757592
commit 13c9f95b50
5 changed files with 102 additions and 27 deletions
@@ -41,6 +41,7 @@ import com.intellij.psi.impl.source.javadoc.PsiDocMethodOrFieldRef;
import com.intellij.psi.impl.source.resolve.JavaResolveUtil;
import com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil;
import com.intellij.psi.impl.source.tree.java.PsiReferenceExpressionImpl;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.javadoc.PsiDocTagValue;
@@ -83,6 +84,9 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
PsiElement resolved = reference.resolve();
if (resolved instanceof PsiNamedElement) {
myRefCountHolder.registerLocallyReferenced((PsiNamedElement)resolved);
if (resolved instanceof PsiMember) {
myRefCountHolder.registerReference(reference, new CandidateInfo(resolved, PsiSubstitutor.EMPTY));
}
}
}
}
@@ -18,6 +18,8 @@ package com.intellij.codeInsight.daemon.impl.analysis;
import com.intellij.codeInsight.daemon.impl.DaemonProgressIndicator;
import com.intellij.codeInsight.daemon.impl.FileStatusMap;
import com.intellij.codeInsight.daemon.impl.GlobalUsageHelper;
import com.intellij.codeInsight.highlighting.ReadWriteAccessDetector;
import com.intellij.codeInsight.highlighting.ReadWriteUtil;
import com.intellij.codeInspection.deadCode.UnusedDeclarationInspectionBase;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.Project;
@@ -33,7 +35,6 @@ import com.intellij.psi.*;
import com.intellij.psi.util.PsiMatcherImpl;
import com.intellij.psi.util.PsiMatchers;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.ArrayUtilRt;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.containers.Predicate;
@@ -279,21 +280,29 @@ class RefCountHolder {
if (array.isEmpty()) return false;
for (PsiReference ref : array) {
PsiElement refElement = ref.getElement();
if (!(refElement instanceof PsiExpression)) { // possible with incomplete code
return true;
}
if (PsiUtil.isAccessedForReading((PsiExpression)refElement)) {
if (refElement.getParent() instanceof PsiExpression &&
refElement.getParent().getParent() instanceof PsiExpressionStatement &&
PsiUtil.isAccessedForWriting((PsiExpression)refElement)) {
continue; // "var++;"
PsiElement resolved = ref.resolve();
if (resolved != null) {
ReadWriteAccessDetector.Access access = ReadWriteUtil.getReadWriteAccess(new PsiElement[]{resolved}, refElement);
if (access == ReadWriteAccessDetector.Access.Read || access == ReadWriteAccessDetector.Access.ReadWrite) {
if (isJustIncremented(access, refElement)) continue;
return true;
}
return true;
}
}
return false;
}
// "var++;"
private static boolean isJustIncremented(@NotNull ReadWriteAccessDetector.Access access, @NotNull PsiElement refElement) {
if (access == ReadWriteAccessDetector.Access.ReadWrite &&
refElement instanceof PsiExpression &&
refElement.getParent() instanceof PsiExpression &&
refElement.getParent().getParent() instanceof PsiExpressionStatement) {
return true;
}
return false;
}
boolean isReferencedForWrite(@NotNull PsiVariable variable) {
Collection<PsiReference> array;
synchronized (myLocalRefsMap) {
@@ -305,8 +314,13 @@ class RefCountHolder {
if (!(refElement instanceof PsiExpression)) { // possible with incomplete code
return true;
}
if (PsiUtil.isAccessedForWriting((PsiExpression)refElement)) {
return true;
PsiElement resolved = ref.resolve();
if (resolved != null) {
ReadWriteAccessDetector.Access access = ReadWriteUtil.getReadWriteAccess(new PsiElement[]{resolved}, refElement);
if (access == ReadWriteAccessDetector.Access.Write || access == ReadWriteAccessDetector.Access.ReadWrite) {
return true;
}
}
}
return false;
@@ -50,4 +50,31 @@ class PrivateClassTest {
f(b, param);
}
}
class IncrementedButNeverAccessed {
private int <warning descr="Private field 'ffff' is assigned but never accessed">ffff</warning>;
void foo(int p) {
if (p == 0) return;
ffff++;
}
}
class IncrementedAndPassed {
private int ffff;
void foo(int p) {
if (p == 0) return;
foo(ffff++);
}
}
class IncrementedAndRead{
private int ffff;
void foo(int p) {
if (p == 0) return;
p = ffff++;
if (p == 0) foo(p);
}
}
}
@@ -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 com.intellij.codeInsight.highlighting;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
public class ReadWriteUtil {
public static ReadWriteAccessDetector.Access getReadWriteAccess(@NotNull PsiElement[] primaryElements, @NotNull PsiElement element) {
for (ReadWriteAccessDetector detector : Extensions.getExtensions(ReadWriteAccessDetector.EP_NAME)) {
if (isReadWriteAccessibleElements(primaryElements, detector)) {
return detector.getExpressionAccess(element);
}
}
return null;
}
private static boolean isReadWriteAccessibleElements(@NotNull PsiElement[] primaryElements, @NotNull ReadWriteAccessDetector detector) {
for (PsiElement element : primaryElements) {
if (!detector.isReadWriteAccessible(element)) return false;
}
return true;
}
}
@@ -16,7 +16,7 @@
package com.intellij.usages;
import com.intellij.codeInsight.highlighting.ReadWriteAccessDetector;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.codeInsight.highlighting.ReadWriteUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.SmartPointerManager;
import com.intellij.psi.SmartPsiElementPointer;
@@ -119,13 +119,11 @@ public class UsageInfoToUsageConverter {
public static Usage convert(@NotNull PsiElement[] primaryElements, @NotNull UsageInfo usageInfo) {
PsiElement usageElement = usageInfo.getElement();
if (usageElement != null && primaryElements.length != 0) {
for(ReadWriteAccessDetector detector: Extensions.getExtensions(ReadWriteAccessDetector.EP_NAME)) {
if (isReadWriteAccessibleElements(primaryElements, detector)) {
final ReadWriteAccessDetector.Access rwAccess = detector.getExpressionAccess(usageElement);
return new ReadWriteAccessUsageInfo2UsageAdapter(usageInfo,
rwAccess != ReadWriteAccessDetector.Access.Write,
rwAccess != ReadWriteAccessDetector.Access.Read);
}
ReadWriteAccessDetector.Access rwAccess = ReadWriteUtil.getReadWriteAccess(primaryElements, usageElement);
if (rwAccess != null) {
return new ReadWriteAccessUsageInfo2UsageAdapter(usageInfo,
rwAccess != ReadWriteAccessDetector.Access.Write,
rwAccess != ReadWriteAccessDetector.Access.Read);
}
}
return new UsageInfo2UsageAdapter(usageInfo);
@@ -140,15 +138,9 @@ public class UsageInfoToUsageConverter {
return usages;
}
@NotNull
public static Usage[] convert(@NotNull final PsiElement[] primaryElements, @NotNull UsageInfo[] usageInfos) {
return ContainerUtil.map(usageInfos, info -> convert(primaryElements, info), new Usage[usageInfos.length]);
}
private static boolean isReadWriteAccessibleElements(@NotNull PsiElement[] elements, @NotNull ReadWriteAccessDetector detector) {
for (PsiElement element : elements) {
if (!detector.isReadWriteAccessible(element)) return false;
}
return true;
}
}