1 11 package org.eclipse.jdt.internal.compiler.flow; 12 13 import java.util.ArrayList ; 14 15 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; 16 import org.eclipse.jdt.internal.compiler.ast.ASTNode; 17 import org.eclipse.jdt.internal.compiler.ast.SubRoutineStatement; 18 import org.eclipse.jdt.internal.compiler.ast.TryStatement; 19 import org.eclipse.jdt.internal.compiler.codegen.ObjectCache; 20 import org.eclipse.jdt.internal.compiler.lookup.BlockScope; 21 import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; 22 import org.eclipse.jdt.internal.compiler.lookup.MethodScope; 23 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; 24 import org.eclipse.jdt.internal.compiler.lookup.Scope; 25 import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; 26 27 31 public class ExceptionHandlingFlowContext extends FlowContext { 32 33 public final static int BitCacheSize = 32; 35 public ReferenceBinding[] handledExceptions; 36 int[] isReached; 37 int[] isNeeded; 38 UnconditionalFlowInfo[] initsOnExceptions; 39 ObjectCache indexes = new ObjectCache(); 40 boolean isMethodContext; 41 42 public UnconditionalFlowInfo initsOnReturn; 43 44 public ArrayList extendedExceptions; 46 47 public ExceptionHandlingFlowContext( 48 FlowContext parent, 49 ASTNode associatedNode, 50 ReferenceBinding[] handledExceptions, 51 BlockScope scope, 52 UnconditionalFlowInfo flowInfo) { 53 54 super(parent, associatedNode); 55 this.isMethodContext = scope == scope.methodScope(); 56 this.handledExceptions = handledExceptions; 57 int count = handledExceptions.length, cacheSize = (count / ExceptionHandlingFlowContext.BitCacheSize) + 1; 58 this.isReached = new int[cacheSize]; this.isNeeded = new int[cacheSize]; this.initsOnExceptions = new UnconditionalFlowInfo[count]; 61 for (int i = 0; i < count; i++) { 62 this.indexes.put(handledExceptions[i], i); int cacheIndex = i / ExceptionHandlingFlowContext.BitCacheSize, bitMask = 1 << (i % ExceptionHandlingFlowContext.BitCacheSize); 64 if (handledExceptions[i].isUncheckedException(true)) { 65 this.isReached[cacheIndex] |= bitMask; 66 this.initsOnExceptions[i] = flowInfo.unconditionalCopy(); 67 } else { 68 this.initsOnExceptions[i] = FlowInfo.DEAD_END; 69 } 70 } 71 System.arraycopy(this.isReached, 0, this.isNeeded, 0, cacheSize); 72 this.initsOnReturn = FlowInfo.DEAD_END; 73 } 74 75 public void complainIfUnusedExceptionHandlers(AbstractMethodDeclaration method) { 76 MethodScope scope = method.scope; 77 if ((method.binding.modifiers & (ExtraCompilerModifiers.AccOverriding | ExtraCompilerModifiers.AccImplementing)) != 0 79 && !scope.compilerOptions().reportUnusedDeclaredThrownExceptionWhenOverriding) { 80 return; 81 } 82 83 for (int i = 0, count = this.handledExceptions.length; i < count; i++) { 85 int index = this.indexes.get(this.handledExceptions[i]); 86 int cacheIndex = index / ExceptionHandlingFlowContext.BitCacheSize; 87 int bitMask = 1 << (index % ExceptionHandlingFlowContext.BitCacheSize); 88 if ((this.isReached[cacheIndex] & bitMask) == 0) { 89 scope.problemReporter().unusedDeclaredThrownException( 90 this.handledExceptions[index], 91 method, 92 method.thrownExceptions[index]); 93 } 94 } 95 } 96 97 public void complainIfUnusedExceptionHandlers(BlockScope scope,TryStatement tryStatement) { 98 for (int i = 0, count = this.handledExceptions.length; i < count; i++) { 100 int index = this.indexes.get(this.handledExceptions[i]); 101 int cacheIndex = index / ExceptionHandlingFlowContext.BitCacheSize; 102 int bitMask = 1 << (index % ExceptionHandlingFlowContext.BitCacheSize); 103 if ((this.isReached[cacheIndex] & bitMask) == 0) { 104 scope.problemReporter().unreachableCatchBlock( 105 this.handledExceptions[index], 106 tryStatement.catchArguments[index].type); 107 } else { 108 if ((this.isNeeded[cacheIndex] & bitMask) == 0) { 109 scope.problemReporter().hiddenCatchBlock( 110 this.handledExceptions[index], 111 tryStatement.catchArguments[index].type); 112 } 113 } 114 } 115 } 116 117 public String individualToString() { 118 StringBuffer buffer = new StringBuffer ("Exception flow context"); int length = this.handledExceptions.length; 120 for (int i = 0; i < length; i++) { 121 int cacheIndex = i / ExceptionHandlingFlowContext.BitCacheSize; 122 int bitMask = 1 << (i % ExceptionHandlingFlowContext.BitCacheSize); 123 buffer.append('[').append(this.handledExceptions[i].readableName()); 124 if ((this.isReached[cacheIndex] & bitMask) != 0) { 125 if ((this.isNeeded[cacheIndex] & bitMask) == 0) { 126 buffer.append("-masked"); } else { 128 buffer.append("-reached"); } 130 } else { 131 buffer.append("-not reached"); } 133 buffer.append('-').append(this.initsOnExceptions[i].toString()).append(']'); 134 } 135 buffer.append("[initsOnReturn -").append(this.initsOnReturn.toString()).append(']'); return buffer.toString(); 137 } 138 139 public UnconditionalFlowInfo initsOnException(ReferenceBinding exceptionType) { 140 int index; 141 if ((index = this.indexes.get(exceptionType)) < 0) { 142 return FlowInfo.DEAD_END; 143 } 144 return this.initsOnExceptions[index]; 145 } 146 147 public UnconditionalFlowInfo initsOnReturn(){ 148 return this.initsOnReturn; 149 } 150 151 155 public void mergeUnhandledException(TypeBinding newException){ 156 if (this.extendedExceptions == null){ 157 this.extendedExceptions = new ArrayList (5); 158 for (int i = 0; i < this.handledExceptions.length; i++){ 159 this.extendedExceptions.add(this.handledExceptions[i]); 160 } 161 } 162 boolean isRedundant = false; 163 164 for(int i = this.extendedExceptions.size()-1; i >= 0; i--){ 165 switch(Scope.compareTypes(newException, (TypeBinding)this.extendedExceptions.get(i))){ 166 case Scope.MORE_GENERIC : 167 this.extendedExceptions.remove(i); 168 break; 169 case Scope.EQUAL_OR_MORE_SPECIFIC : 170 isRedundant = true; 171 break; 172 case Scope.NOT_RELATED : 173 break; 174 } 175 } 176 if (!isRedundant){ 177 this.extendedExceptions.add(newException); 178 } 179 } 180 181 public void recordHandlingException( 182 ReferenceBinding exceptionType, 183 UnconditionalFlowInfo flowInfo, 184 TypeBinding raisedException, 185 ASTNode invocationSite, 186 boolean wasAlreadyDefinitelyCaught) { 187 188 int index = this.indexes.get(exceptionType); 189 int cacheIndex = index / ExceptionHandlingFlowContext.BitCacheSize; 191 int bitMask = 1 << (index % ExceptionHandlingFlowContext.BitCacheSize); 192 if (!wasAlreadyDefinitelyCaught) { 193 this.isNeeded[cacheIndex] |= bitMask; 194 } 195 this.isReached[cacheIndex] |= bitMask; 196 197 this.initsOnExceptions[index] = 198 (this.initsOnExceptions[index].tagBits & FlowInfo.UNREACHABLE) == 0 ? 199 this.initsOnExceptions[index].mergedWith(flowInfo): 200 flowInfo.unconditionalCopy(); 201 } 202 203 public void recordReturnFrom(UnconditionalFlowInfo flowInfo) { 204 if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) { 205 if ((this.initsOnReturn.tagBits & FlowInfo.UNREACHABLE) == 0) { 206 this.initsOnReturn = this.initsOnReturn.mergedWith(flowInfo); 207 } 208 else { 209 this.initsOnReturn = (UnconditionalFlowInfo) flowInfo.copy(); 210 } 211 } 212 } 213 214 221 public SubRoutineStatement subroutine() { 222 if (this.associatedNode instanceof SubRoutineStatement) { 223 if (this.parent.subroutine() == this.associatedNode) 225 return null; 226 return (SubRoutineStatement) this.associatedNode; 227 } 228 return null; 229 } 230 } 231 | Popular Tags |