1 11 12 package org.eclipse.jdt.internal.corext.refactoring.generics; 13 14 import java.util.ArrayList ; 15 import java.util.Arrays ; 16 import java.util.Collection ; 17 import java.util.Collections ; 18 import java.util.HashSet ; 19 import java.util.Iterator ; 20 import java.util.List ; 21 import java.util.Stack ; 22 23 import org.eclipse.core.runtime.Assert; 24 25 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.GenericType; 26 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TType; 27 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.CollectionElementVariable2; 28 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ConstraintVariable2; 29 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.SubTypeConstraint2; 30 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.TypeEquivalenceSet; 31 32 33 public class ParametricStructureComputer { 34 public static class ParametricStructure { 35 36 public static final ParametricStructure NONE= new ParametricStructure(); 37 38 private final GenericType fBase; 39 private final ParametricStructure[] fParameters; 40 41 public ParametricStructure(GenericType base) { 42 if (base == null) 43 throw new NullPointerException (); 44 fBase= base; 45 fParameters= new ParametricStructure[base.getTypeParameters().length]; 46 } 47 48 private ParametricStructure() { 49 fBase= null; 50 fParameters= new ParametricStructure[0]; 51 } 52 53 public ParametricStructure[] getParameters() { 54 return fParameters; 55 } 56 57 public GenericType getBase() { 58 return fBase; 59 } 60 61 public String toString() { 62 if (this == NONE) 63 return "NONE"; else 65 return "ParamStructure " + fBase.toString() + '<' + Arrays.asList(fParameters) + '>'; } 67 } 68 69 70 private static final boolean DEBUG_INITIALIZATION= false; 71 72 78 private final ElementStructureEnvironment fElemStructureEnv= new ElementStructureEnvironment(); 79 private final ConstraintVariable2[] fAllConstraintVariables; 80 private InferTypeArgumentsTCModel fTCModel; 81 82 public ParametricStructureComputer(ConstraintVariable2[] allConstraintVariables, InferTypeArgumentsTCModel tcModel) { 83 fAllConstraintVariables= allConstraintVariables; 84 fTCModel= tcModel; 85 } 86 87 public ElementStructureEnvironment getElemStructureEnv() { 88 return fElemStructureEnv; 89 } 90 91 private void dumpContainerStructure() { 92 System.out.println("\n*** Container Structure: ***\n"); for (int i= 0; i < fAllConstraintVariables.length; i++) { 94 ConstraintVariable2 v= fAllConstraintVariables[i]; 95 if (elemStructure(v) != null && !(elemStructure(v) == ParametricStructure.NONE)) 96 System.out.println("elemStructure(" + v.toString() + ") = " + elemStructure(v)); } 98 System.out.println(); 99 } 100 101 102 private Stack fWorkList2= new Stack (); 103 104 105 private void setStructureAndPush(ConstraintVariable2 v, ParametricStructure structure) { 106 setElemStructure(v, structure); 107 fWorkList2.push(v); 108 } 109 110 private void initializeContainerStructure(){ 112 if (DEBUG_INITIALIZATION) 113 System.out.println(" *** Seeding container structure ***"); for (int i= 0; i < fAllConstraintVariables.length; i++) { 115 ConstraintVariable2 v= fAllConstraintVariables[i]; 116 TType varType= declaredTypeOf(v); 117 118 if (varType != null) { 119 if (isParametricType(varType) && !isUnmodifiableFieldOrMethod(v)) { 124 if (DEBUG_INITIALIZATION) System.out.println("Entity has container structure: " + v); setStructureAndPush(v, newParametricType(varType)); 126 } else if (varType != null && !mightBeParametric(varType)) { 127 if (DEBUG_INITIALIZATION) System.out.println("Entity DOES NOT have container structure: " + v); setStructureAndPush(v, ParametricStructure.NONE); 130 } 131 } else { 133 147 } 161 } 162 } 167 168 protected static TType declaredTypeOf(ConstraintVariable2 cv) { 169 return cv.getType(); 171 172 } 191 192 private boolean mightBeParametric(TType type) { 193 return isParametricType(type); } 195 196 private void computeContainerStructure() { 197 if (DEBUG_INITIALIZATION) 198 System.out.println("\n*** Computing Container Structure ***\n"); 200 initializeContainerStructure(); 201 202 if (DEBUG_INITIALIZATION) 203 dumpContainerStructure(); 204 205 while (!fWorkList2.isEmpty()) { 206 ConstraintVariable2 v= (ConstraintVariable2) fWorkList2.pop(); 207 List usedIn= fTCModel.getUsedIn(v); 208 209 for(Iterator iter= usedIn.iterator(); iter.hasNext(); ) { 210 SubTypeConstraint2 stc= (SubTypeConstraint2) iter.next(); 211 212 ConstraintVariable2 lhs= stc.getLeft(); 213 ConstraintVariable2 rhs= stc.getRight(); 214 215 unifyContainerStructure(lhs, rhs); 216 } 217 218 TypeEquivalenceSet typeEquivalenceSet= v.getTypeEquivalenceSet(); 219 if (typeEquivalenceSet != null) { 220 ConstraintVariable2[] contributingVariables= typeEquivalenceSet.getContributingVariables(); 221 for (int i= 0; i + 1 < contributingVariables.length; i++) { 222 ConstraintVariable2 first= contributingVariables[i]; 223 ConstraintVariable2 second= contributingVariables[i + 1]; 224 225 unifyContainerStructure(first, second); 226 } 227 } 228 } 229 if (DEBUG_INITIALIZATION) 230 dumpContainerStructure(); 231 } 232 233 private void unifyContainerStructure(ConstraintVariable2 lhs, ConstraintVariable2 rhs) { 234 if (isUnmodifiableFieldOrMethod(lhs) || isUnmodifiableFieldOrMethod(rhs)) 236 return; 237 238 if (DEBUG_INITIALIZATION) 239 System.out.println("Examining constraint " + lhs + " {" + elemStructure(lhs) + "} <= " + rhs + " {" + elemStructure(rhs) + "}"); 241 if (updateStructureOfVar(lhs, elemStructure(rhs), TypeOperator.SubType)) { 242 if (lhs instanceof CollectionElementVariable2) 243 updateParentContainerStructureFrom((CollectionElementVariable2) lhs, rhs); 244 updateElementVarStructureFromParent(lhs); 245 } 246 if (updateStructureOfVar(rhs, elemStructure(lhs), TypeOperator.SuperType)) { 247 if (rhs instanceof CollectionElementVariable2) 248 updateParentContainerStructureFrom((CollectionElementVariable2) rhs, lhs); 249 updateElementVarStructureFromParent(rhs); 250 } 251 } 252 253 private ParametricStructure newParametricType(TType varType) { 254 GenericType genericType= (GenericType) varType.getTypeDeclaration(); 256 return new ParametricStructure(genericType); 257 } 258 259 private boolean isUnmodifiableFieldOrMethod(ConstraintVariable2 v) { 260 return false; } 262 263 private boolean isParametricType(TType type) { 264 return type.isParameterizedType() 265 || type.isGenericType() 266 || (type.isRawType() && type.getTypeDeclaration().isGenericType()) ; 267 } 268 269 273 private boolean updateStructureOfIthParamFrom(ParametricStructure structure1, int i, ParametricStructure otherStructure) { 274 if ((otherStructure == null)) return false; 276 277 Assert.isTrue(structure1 != otherStructure, "updateStructureOfIthParamFrom(): attempt to unify ith param of a parametric type with itself!"); 279 ParametricStructure param1= structure1.getParameters()[i]; 280 boolean param1Unknown= (param1 == null); 281 282 if (param1Unknown) { 283 if (DEBUG_INITIALIZATION) 284 System.out.println(" setting param " + i + " of " + structure1 + " to " + otherStructure); structure1.getParameters()[i]= otherStructure; 286 return true; 287 } 288 289 boolean paramStructured= !(param1 == ParametricStructure.NONE); 290 boolean otherStructured= !(otherStructure == ParametricStructure.NONE); 291 292 if (paramStructured && otherStructured) { if (param1.getBase().equals(otherStructure.getBase())) 297 return updateStructureOfType(param1, otherStructure); 298 else { 299 structure1.getParameters()[i]= ParametricStructure.NONE; 300 return true; 301 } 302 } 303 304 return false; 305 } 306 307 311 private void updateElementVarStructureFromParent(ConstraintVariable2 v) { 312 if (elemStructure(v) != ParametricStructure.NONE && fTCModel.getElementVariables(v).size() > 0) { 314 ParametricStructure t= elemStructure(v); 315 for(Iterator iterator=fTCModel.getElementVariables(v).values().iterator(); iterator.hasNext(); ) { 316 CollectionElementVariable2 typeVar= (CollectionElementVariable2) iterator.next(); 317 int declarationTypeVariableIndex= typeVar.getDeclarationTypeVariableIndex(); 318 319 if (declarationTypeVariableIndex != CollectionElementVariable2.NOT_DECLARED_TYPE_VARIABLE_INDEX) 320 updateStructureOfVar(typeVar, t.getParameters()[declarationTypeVariableIndex], TypeOperator.Equals); 321 } 322 } 323 } 324 325 331 private void updateParentContainerStructureFrom(CollectionElementVariable2 elemVar, ConstraintVariable2 v1) { 332 ConstraintVariable2 elemContainer= elemVar.getParentConstraintVariable(); 333 334 ParametricStructure elemContainerStructure= elemStructure(elemContainer); 339 if (elemContainerStructure == ParametricStructure.NONE) 340 return; 341 342 if (false) { 343 if (v1 instanceof CollectionElementVariable2) { 344 CollectionElementVariable2 ev1= (CollectionElementVariable2) v1; 346 ConstraintVariable2 v1Container= ev1.getParentConstraintVariable(); 347 348 if (elemStructure(v1Container) == ParametricStructure.NONE) 349 setStructureAndPush(elemContainer, ParametricStructure.NONE); 350 return; 351 } 352 } 353 354 if (elemContainerStructure == null) { elemContainerStructure= newParametricType(elemContainer.getType()); 356 setStructureAndPush(elemContainer, elemContainerStructure); 357 } 358 ParametricStructure v1Structure= elemStructure(v1); 359 int parmIdx= elemVar.getDeclarationTypeVariableIndex(); if (parmIdx == CollectionElementVariable2.NOT_DECLARED_TYPE_VARIABLE_INDEX) 361 return; 363 if (elemContainerStructure == v1Structure || containsSubStructure(v1Structure, elemContainerStructure)) { if (!(elemStructure(elemVar) == ParametricStructure.NONE)) 365 setStructureAndPush(elemVar, ParametricStructure.NONE); 366 if (elemContainerStructure.getParameters()[parmIdx] == null) { 367 elemContainerStructure.getParameters()[parmIdx]= ParametricStructure.NONE; 368 fWorkList2.push(elemContainer); 369 } 370 } else if (updateStructureOfIthParamFrom(elemContainerStructure, parmIdx, v1Structure)) { 371 setStructureAndPush(elemVar, elemContainerStructure.getParameters()[parmIdx]); 372 fWorkList2.push(elemContainer); 373 if (DEBUG_INITIALIZATION) 374 System.out.println(" updated structure of " + elemContainer + " to " + elemContainerStructure); } 376 } 377 378 private boolean containsSubStructure(ParametricStructure containingStructure, ParametricStructure subStructure) { 379 if (containingStructure == null) 380 return false; 381 382 ParametricStructure[] parameters= containingStructure.getParameters(); 383 for (int i= 0; i < parameters.length; i++) { 384 ParametricStructure parameter= parameters[i]; 385 if (parameter == subStructure) 386 return true; 387 else if (containsSubStructure(parameter, subStructure)) 388 return true; 389 } 390 return false; 391 } 392 393 398 private boolean updateStructureOfType(ParametricStructure type1, ParametricStructure type2) { 399 if (type1 == null || type2 == null) 400 return false; 401 402 ParametricStructure[] parms1= type1.getParameters(); 403 ParametricStructure[] parms2= type2.getParameters(); 404 boolean someChange= false; 405 406 Assert.isTrue(parms1.length == parms2.length); 407 408 for(int i=0; i < parms1.length; i++) { 409 if (type1 == parms2[i]) { if (parms1[i] != ParametricStructure.NONE) { 411 parms1[i]= ParametricStructure.NONE; 412 someChange= true; 413 } 414 } else if (updateStructureOfIthParamFrom(type1, i, parms2[i])) 415 someChange= true; 416 } 417 return someChange; 418 } 419 420 static class TypeOperator { 421 private final String fOp; 423 private TypeOperator(String op) { 424 fOp= op; 425 } 426 static public TypeOperator Equals= new TypeOperator("=^="); static public TypeOperator SubType= new TypeOperator("<="); static public TypeOperator SuperType= new TypeOperator("=>"); public String toString() { 430 return fOp; 431 } 432 } 433 434 439 private boolean updateStructureOfVar(ConstraintVariable2 v, ParametricStructure type2, TypeOperator op) { 440 if ((type2 == null)) return false ; 442 443 ParametricStructure vStructure= elemStructure(v); 444 boolean vStructureUnknown= (vStructure == null); 445 boolean type2Structured= type2 != ParametricStructure.NONE; 446 447 if (vStructureUnknown) { 448 if (DEBUG_INITIALIZATION) 449 System.out.println(" setting structure of " + v + " to " + type2); setStructureAndPush(v, type2); 451 return true; 452 } 453 454 boolean vStructured= vStructure != ParametricStructure.NONE; 455 456 if (vStructured && !type2Structured) { 457 if (op == TypeOperator.Equals || op == TypeOperator.SuperType) { 462 setStructureAndPush(v, type2); 463 return true; 464 } 465 } else if (vStructured && type2Structured) { if (!vStructure.getBase().equals(type2.getBase())) { if (op == TypeOperator.SuperType) { setStructureAndPush(v, ParametricStructure.NONE); 472 return true; 473 } 474 } else if (updateStructureOfType(vStructure, type2)) { 475 fWorkList2.push(v); 476 return true; 477 } 478 } 479 return false; 480 } 481 482 private void setElemStructure(ConstraintVariable2 v, ParametricStructure t) { 483 fElemStructureEnv.setElemStructure(v, t); 484 } 485 486 private ParametricStructure elemStructure(ConstraintVariable2 v) { 487 return fElemStructureEnv.elemStructure(v); 488 } 489 490 public Collection createElemConstraintVariables() { 491 Collection newVars= new HashSet (); 492 493 computeContainerStructure(); 494 495 if (DEBUG_INITIALIZATION) 496 System.out.println("\n*** Creating Element Variables: ***\n"); 498 for(int i= 0; i < fAllConstraintVariables.length; i++) { 499 newVars.addAll(createVariablesFor(fAllConstraintVariables[i])); 500 } 501 502 return newVars; 516 } 517 518 private Collection createVariablesFor(ConstraintVariable2 v) { 519 ParametricStructure t= elemStructure(v); 520 521 if (t == null || t == ParametricStructure.NONE) 522 return Collections.EMPTY_LIST; 523 524 ParametricStructure parmType= t; 525 TType base = parmType.getBase(); 526 if (isParametricType(base)) { 527 return createAndInitVars(v, parmType); 528 } 529 throw new IllegalStateException ("Attempt to create element variables for parametric variable of unknown type: " + parmType); } 531 532 private Collection getElementVariables(GenericType base, ConstraintVariable2 parent) { 533 fTCModel.makeElementVariables(parent, base); 534 return fTCModel.getElementVariables(parent).values(); 535 } 536 537 private Collection createAndInitVars(ConstraintVariable2 v, ParametricStructure parmType) { 538 Collection elementVars= getElementVariables(parmType.getBase(), v); 541 Collection result= createVars(elementVars, parmType.getParameters()); 543 return result; 544 } 545 546 private Collection createVars(Collection cvs, ParametricStructure[] parms) { 547 if (parms.length > 0) { for (Iterator iter= cvs.iterator(); iter.hasNext(); ) { 550 CollectionElementVariable2 childVar= (CollectionElementVariable2) iter.next(); 551 int declarationTypeVariableIndex= childVar.getDeclarationTypeVariableIndex(); 552 553 if (declarationTypeVariableIndex != CollectionElementVariable2.NOT_DECLARED_TYPE_VARIABLE_INDEX) 554 setElemStructure(childVar, parms[declarationTypeVariableIndex]); 555 } 556 } else { 557 for (Iterator iter= cvs.iterator(); iter.hasNext(); ) { 558 CollectionElementVariable2 childVar= (CollectionElementVariable2) iter.next(); 559 int declarationTypeVariableIndex= childVar.getDeclarationTypeVariableIndex(); 560 561 if (declarationTypeVariableIndex != CollectionElementVariable2.NOT_DECLARED_TYPE_VARIABLE_INDEX) 562 setElemStructure(childVar, ParametricStructure.NONE); 563 } 564 } 565 List result= new ArrayList (cvs.size() * 2); for (Iterator iter= cvs.iterator(); iter.hasNext(); ) { 567 CollectionElementVariable2 childVar= (CollectionElementVariable2) iter.next(); 568 int declarationTypeVariableIndex= childVar.getDeclarationTypeVariableIndex(); 569 570 if (declarationTypeVariableIndex != CollectionElementVariable2.NOT_DECLARED_TYPE_VARIABLE_INDEX) { 571 result.add(childVar); 572 result.addAll(createVariablesFor(childVar)); 573 } 574 } 575 return result; 576 } 577 } 578 | Popular Tags |