Lines 14-19
import java.util.HashMap;
Link Here
|
14 |
import java.util.Iterator; |
14 |
import java.util.Iterator; |
15 |
import java.util.Map; |
15 |
import java.util.Map; |
16 |
import java.util.Map.Entry; |
16 |
import java.util.Map.Entry; |
|
|
17 |
import java.util.Set; |
17 |
|
18 |
|
18 |
import org.eclipse.jdt.internal.compiler.codegen.CodeStream; |
19 |
import org.eclipse.jdt.internal.compiler.codegen.CodeStream; |
19 |
import org.eclipse.jdt.internal.compiler.flow.FlowContext; |
20 |
import org.eclipse.jdt.internal.compiler.flow.FlowContext; |
Lines 107-112
public class FakedTrackingVariable extends LocalDeclaration {
Link Here
|
107 |
scope.getJavaLangObject(), // dummy, just needs to be a reference type |
108 |
scope.getJavaLangObject(), // dummy, just needs to be a reference type |
108 |
0, |
109 |
0, |
109 |
false); |
110 |
false); |
|
|
111 |
this.binding.declaringScope = scope; |
110 |
this.binding.setConstant(Constant.NotAConstant); |
112 |
this.binding.setConstant(Constant.NotAConstant); |
111 |
this.binding.useFlag = LocalVariableBinding.USED; |
113 |
this.binding.useFlag = LocalVariableBinding.USED; |
112 |
// use a free slot without assigning it: |
114 |
// use a free slot without assigning it: |
Lines 225-230
public class FakedTrackingVariable extends LocalDeclaration {
Link Here
|
225 |
FakedTrackingVariable currentTracker = innerTracker; |
227 |
FakedTrackingVariable currentTracker = innerTracker; |
226 |
while (currentTracker != null) { |
228 |
while (currentTracker != null) { |
227 |
flowInfo.markNullStatus(currentTracker.binding, newStatus); |
229 |
flowInfo.markNullStatus(currentTracker.binding, newStatus); |
|
|
230 |
currentTracker.globalClosingState |= allocation.closeTracker.globalClosingState; |
228 |
currentTracker = currentTracker.innerTracker; |
231 |
currentTracker = currentTracker.innerTracker; |
229 |
} |
232 |
} |
230 |
} |
233 |
} |
Lines 536-581
public class FakedTrackingVariable extends LocalDeclaration {
Link Here
|
536 |
scope.removeTrackingVar(trackVar); |
539 |
scope.removeTrackingVar(trackVar); |
537 |
return flowInfo; |
540 |
return flowInfo; |
538 |
} |
541 |
} |
539 |
trackVar.globalClosingState |= SHARED_WITH_OUTSIDE; |
|
|
540 |
if (scope.methodScope() != trackVar.methodScope) |
541 |
trackVar.globalClosingState |= CLOSED_IN_NESTED_METHOD; |
542 |
// insert info that the tracked resource *may* be closed (by the target method, i.e.) |
542 |
// insert info that the tracked resource *may* be closed (by the target method, i.e.) |
543 |
FlowInfo infoResourceIsClosed = flowInfo.copy(); |
543 |
FlowInfo infoResourceIsClosed = flowInfo.copy(); |
544 |
infoResourceIsClosed.markAsDefinitelyNonNull(trackVar.binding); |
544 |
do { |
|
|
545 |
trackVar.globalClosingState |= SHARED_WITH_OUTSIDE; |
546 |
if (scope.methodScope() != trackVar.methodScope) |
547 |
trackVar.globalClosingState |= CLOSED_IN_NESTED_METHOD; |
548 |
infoResourceIsClosed.markAsDefinitelyNonNull(trackVar.binding); |
549 |
} while ((trackVar = trackVar.innerTracker) != null); |
545 |
return FlowInfo.conditional(flowInfo, infoResourceIsClosed); |
550 |
return FlowInfo.conditional(flowInfo, infoResourceIsClosed); |
546 |
} |
551 |
} |
547 |
return flowInfo; |
552 |
return flowInfo; |
548 |
} |
553 |
} |
549 |
|
554 |
|
|
|
555 |
/** |
556 |
* Pick tracking variables from 'varsOfScope' to establish a proper order of processing: |
557 |
* As much as possible pick wrapper resources before their inner resources. |
558 |
* Also consider cases of wrappers and their inners being declared at different scopes. |
559 |
*/ |
560 |
public static FakedTrackingVariable pickVarForReporting(Set varsOfScope, BlockScope scope, boolean atExit) { |
561 |
if (varsOfScope.isEmpty()) return null; |
562 |
FakedTrackingVariable trackingVar = (FakedTrackingVariable) varsOfScope.iterator().next(); |
563 |
while (trackingVar.outerTracker != null) { |
564 |
// resource is wrapped, is wrapper defined in this scope? |
565 |
if (varsOfScope.contains(trackingVar.outerTracker)) { |
566 |
// resource from same scope, travel up the wrapper chain |
567 |
trackingVar = trackingVar.outerTracker; |
568 |
} else if (atExit) { |
569 |
// at an exit point we report against inner despite a wrapper that may/may not be closed later |
570 |
break; |
571 |
} else { |
572 |
BlockScope outerTrackerScope = trackingVar.outerTracker.binding.declaringScope; |
573 |
if (outerTrackerScope == scope) { |
574 |
// outerTracker is from same scope and already processed -> pick trackingVar now |
575 |
break; |
576 |
} else { |
577 |
// outer resource is from other (outer?) scope |
578 |
Scope currentScope = scope; |
579 |
while ((currentScope = currentScope.parent) instanceof BlockScope) { |
580 |
if (outerTrackerScope == currentScope) { |
581 |
// at end of block pass responsibility for inner resource to outer scope holding a wrapper |
582 |
varsOfScope.remove(trackingVar); // drop this one |
583 |
// pick a next candidate: |
584 |
return pickVarForReporting(varsOfScope, scope, atExit); |
585 |
} |
586 |
} |
587 |
break; // not parent owned -> pick this var |
588 |
} |
589 |
} |
590 |
} |
591 |
varsOfScope.remove(trackingVar); |
592 |
return trackingVar; |
593 |
} |
594 |
|
550 |
public void recordErrorLocation(ASTNode location, int nullStatus) { |
595 |
public void recordErrorLocation(ASTNode location, int nullStatus) { |
551 |
if (this.recordedLocations == null) |
596 |
if (this.recordedLocations == null) |
552 |
this.recordedLocations = new HashMap(); |
597 |
this.recordedLocations = new HashMap(); |
553 |
this.recordedLocations.put(location, new Integer(nullStatus)); |
598 |
this.recordedLocations.put(location, new Integer(nullStatus)); |
554 |
} |
599 |
} |
555 |
|
600 |
|
556 |
public boolean reportRecordedErrors(Scope scope) { |
601 |
public boolean reportRecordedErrors(Scope scope, int mergedStatus) { |
557 |
FakedTrackingVariable current = this; |
602 |
FakedTrackingVariable current = this; |
558 |
while (current.globalClosingState == 0) { |
603 |
while (current.globalClosingState == 0) { |
559 |
current = current.innerTracker; |
604 |
current = current.innerTracker; |
560 |
if (current == null) { |
605 |
if (current == null) { |
561 |
// no relevant state found -> report: |
606 |
// no relevant state found -> report: |
562 |
reportError(scope.problemReporter(), null, FlowInfo.NULL); |
607 |
reportError(scope.problemReporter(), null, mergedStatus); |
563 |
return true; |
608 |
return true; |
564 |
} |
609 |
} |
565 |
} |
610 |
} |
566 |
boolean hasReported = false; |
611 |
boolean hasReported = false; |
567 |
if (this.recordedLocations != null) { |
612 |
if (this.recordedLocations != null) { |
568 |
Iterator locations = this.recordedLocations.entrySet().iterator(); |
613 |
Iterator locations = this.recordedLocations.entrySet().iterator(); |
|
|
614 |
int reportFlags = 0; |
569 |
while (locations.hasNext()) { |
615 |
while (locations.hasNext()) { |
570 |
Map.Entry entry = (Entry) locations.next(); |
616 |
Map.Entry entry = (Entry) locations.next(); |
571 |
reportError(scope.problemReporter(), (ASTNode)entry.getKey(), ((Integer)entry.getValue()).intValue()); |
617 |
reportFlags |= reportError(scope.problemReporter(), (ASTNode)entry.getKey(), ((Integer)entry.getValue()).intValue()); |
572 |
hasReported = true; |
618 |
hasReported = true; |
573 |
} |
619 |
} |
|
|
620 |
if (reportFlags != 0) { |
621 |
// after all locations have been reported, mark as reported to prevent duplicate report via an outer wrapper |
622 |
current = this; |
623 |
do { |
624 |
current.globalClosingState |= reportFlags; |
625 |
} while ((current = current.innerTracker) != null); |
626 |
} |
574 |
} |
627 |
} |
575 |
return hasReported; |
628 |
return hasReported; |
576 |
} |
629 |
} |
577 |
|
630 |
|
578 |
public void reportError(ProblemReporter problemReporter, ASTNode location, int nullStatus) { |
631 |
public int reportError(ProblemReporter problemReporter, ASTNode location, int nullStatus) { |
579 |
// which degree of problem? |
632 |
// which degree of problem? |
580 |
boolean isPotentialProblem = false; |
633 |
boolean isPotentialProblem = false; |
581 |
if (nullStatus == FlowInfo.NULL) { |
634 |
if (nullStatus == FlowInfo.NULL) { |
Lines 587-608
public class FakedTrackingVariable extends LocalDeclaration {
Link Here
|
587 |
// report: |
640 |
// report: |
588 |
if (isPotentialProblem) { |
641 |
if (isPotentialProblem) { |
589 |
if ((this.globalClosingState & (REPORTED_POTENTIAL_LEAK|REPORTED_DEFINITIVE_LEAK)) != 0) |
642 |
if ((this.globalClosingState & (REPORTED_POTENTIAL_LEAK|REPORTED_DEFINITIVE_LEAK)) != 0) |
590 |
return; |
643 |
return 0; |
591 |
problemReporter.potentiallyUnclosedCloseable(this, location); |
644 |
problemReporter.potentiallyUnclosedCloseable(this, location); |
592 |
} else { |
645 |
} else { |
593 |
if ((this.globalClosingState & (REPORTED_DEFINITIVE_LEAK)) != 0) |
646 |
if ((this.globalClosingState & (REPORTED_DEFINITIVE_LEAK)) != 0) |
594 |
return; |
647 |
return 0; |
595 |
problemReporter.unclosedCloseable(this, location); |
648 |
problemReporter.unclosedCloseable(this, location); |
596 |
} |
649 |
} |
597 |
// propagate flag to inners: |
650 |
// propagate flag to inners: |
598 |
if (location == null) { |
651 |
int reportFlag = isPotentialProblem ? REPORTED_POTENTIAL_LEAK : REPORTED_DEFINITIVE_LEAK; |
599 |
int reportFlag = isPotentialProblem ? REPORTED_POTENTIAL_LEAK : REPORTED_DEFINITIVE_LEAK; |
652 |
if (location == null) { // if location != null flags will be set after the loop over locations |
600 |
FakedTrackingVariable current = this; |
653 |
FakedTrackingVariable current = this; |
601 |
while (current != null) { |
654 |
do { |
602 |
current.globalClosingState |= reportFlag; |
655 |
current.globalClosingState |= reportFlag; |
603 |
current = current.innerTracker; |
656 |
} while ((current = current.innerTracker) != null); |
604 |
} |
|
|
605 |
} |
657 |
} |
|
|
658 |
return reportFlag; |
606 |
} |
659 |
} |
607 |
|
660 |
|
608 |
public void reportExplicitClosing(ProblemReporter problemReporter) { |
661 |
public void reportExplicitClosing(ProblemReporter problemReporter) { |
Lines 611-614
public class FakedTrackingVariable extends LocalDeclaration {
Link Here
|
611 |
problemReporter.explicitlyClosedAutoCloseable(this); |
664 |
problemReporter.explicitlyClosedAutoCloseable(this); |
612 |
} |
665 |
} |
613 |
} |
666 |
} |
|
|
667 |
|
668 |
public void resetReportingBits() { |
669 |
FakedTrackingVariable current = this; |
670 |
while (current != null) { |
671 |
current.globalClosingState &= ~(REPORTED_POTENTIAL_LEAK|REPORTED_DEFINITIVE_LEAK); |
672 |
current = current.innerTracker; |
673 |
} |
674 |
} |
614 |
} |
675 |
} |