1 /*******************************************************************************
2  * Copyright (c) 2000, 2011 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 
15 
16 package org.eclipse.jdt.internal.corext.refactoring.typeconstraints;
17 
18 import java.util.HashMap;
19 import java.util.Map;
20 
21 import org.eclipse.jdt.core.dom.ITypeBinding;
22 
23 public class TypeConstraintFactory implements ITypeConstraintFactory {
24 
25 	private Map<ConstraintVariable, Map<ConstraintVariable, Map<ConstraintOperator, SimpleTypeConstraint>>> fSimpleConstraints= new HashMap<>();
26 	private Map<ConstraintVariable, Map<String, CompositeOrTypeConstraint>> fOrConstraints= new HashMap<>();
27 
28 	protected static final boolean PRINT_STATS= false;
29 	protected int fNrCreated= 0;
30 	protected int fNrFiltered= 0;
31 	protected int fNrRetrieved= 0;
32 
33 	// Only to be called by the createXXXConstraint() methods
createSimpleTypeConstraint(ConstraintVariable v1, ConstraintVariable v2, ConstraintOperator operator)34 	private SimpleTypeConstraint createSimpleTypeConstraint(ConstraintVariable v1, ConstraintVariable v2, ConstraintOperator operator) {
35 		if (fSimpleConstraints.containsKey(v1)){
36 			Map<ConstraintVariable, Map<ConstraintOperator, SimpleTypeConstraint>> m2= fSimpleConstraints.get(v1);
37 			if (m2.containsKey(v2)){
38 				Map<ConstraintOperator, SimpleTypeConstraint> m3= m2.get(v2);
39 				if (m3.containsKey(operator)){
40 					if (PRINT_STATS) fNrRetrieved++;
41 					if (PRINT_STATS) dumpStats();
42 					return m3.get(operator);
43 				} else {
44 					return storeConstraint(v1, v2, operator, m3);
45 				}
46 			} else {
47 				Map<ConstraintOperator, SimpleTypeConstraint> m3= new HashMap<>();
48 				m2.put(v2, m3);
49 				return storeConstraint(v1, v2, operator, m3);
50 			}
51 		} else {
52 			Map<ConstraintVariable, Map<ConstraintOperator, SimpleTypeConstraint>> m2= new HashMap<>();
53 			fSimpleConstraints.put(v1, m2);
54 			Map<ConstraintOperator, SimpleTypeConstraint> m3= new HashMap<>();
55 			m2.put(v2, m3);
56 			return storeConstraint(v1, v2, operator, m3);
57 		}
58 	}
59 
storeConstraint(ConstraintVariable v1, ConstraintVariable v2, ConstraintOperator operator, Map<ConstraintOperator, SimpleTypeConstraint> m3)60 	private SimpleTypeConstraint storeConstraint(ConstraintVariable v1, ConstraintVariable v2, ConstraintOperator operator, Map<ConstraintOperator, SimpleTypeConstraint> m3) {
61 		SimpleTypeConstraint constraint= new SimpleTypeConstraint(v1, v2, operator);
62 		m3.put(operator, constraint);
63 		if (PRINT_STATS) fNrCreated++;
64 		if (PRINT_STATS) dumpStats();
65 		return constraint;
66 	}
67 
createConstraint(ConstraintVariable v1, ConstraintVariable v2, ConstraintOperator operator)68 	public ITypeConstraint[] createConstraint(ConstraintVariable v1, ConstraintVariable v2, ConstraintOperator operator){
69 		if (filter(v1, v2, operator)){
70 			return new ITypeConstraint[0];
71 		} else {
72 			return new ITypeConstraint[]{ createSimpleTypeConstraint(v1, v2, operator) };
73 		}
74 	}
75 
76 	@Override
createSubtypeConstraint(ConstraintVariable v1, ConstraintVariable v2)77 	public ITypeConstraint[] createSubtypeConstraint(ConstraintVariable v1, ConstraintVariable v2){
78 		return createConstraint(v1, v2, ConstraintOperator.createSubTypeOperator());
79 	}
80 
81 	@Override
createStrictSubtypeConstraint(ConstraintVariable v1, ConstraintVariable v2)82 	public ITypeConstraint[] createStrictSubtypeConstraint(ConstraintVariable v1, ConstraintVariable v2){
83 		return createConstraint(v1, v2, ConstraintOperator.createStrictSubtypeOperator());
84 	}
85 
86 	@Override
createEqualsConstraint(ConstraintVariable v1, ConstraintVariable v2)87 	public ITypeConstraint[] createEqualsConstraint(ConstraintVariable v1, ConstraintVariable v2){
88 		return createConstraint(v1, v2, ConstraintOperator.createEqualsOperator());
89 	}
90 
91 	@Override
createDefinesConstraint(ConstraintVariable v1, ConstraintVariable v2)92 	public ITypeConstraint[] createDefinesConstraint(ConstraintVariable v1, ConstraintVariable v2){
93 		return createConstraint(v1, v2, ConstraintOperator.createDefinesOperator());
94 	}
95 
96 	/**
97 	 * {@inheritDoc}
98 	 * Avoid creating constraints involving primitive types and self-constraints.
99 	 */
100 	@Override
filter(ConstraintVariable v1, ConstraintVariable v2, ConstraintOperator operator)101 	public boolean filter(ConstraintVariable v1, ConstraintVariable v2, ConstraintOperator operator) {
102 		if ((v1.getBinding() != null && v1.getBinding().isPrimitive() &&
103 				v2.getBinding() != null && v2.getBinding().isPrimitive()) ||
104 					v1 == v2) {
105 			if (PRINT_STATS) fNrFiltered++;
106 			if (PRINT_STATS) dumpStats();
107 			return true;
108 		}
109 		return false;
110 	}
111 
112 	@Override
createCompositeOrTypeConstraint(ITypeConstraint[] constraints)113 	public CompositeOrTypeConstraint createCompositeOrTypeConstraint(ITypeConstraint[] constraints){
114 		ConstraintVariable left= ((SimpleTypeConstraint)constraints[0]).getLeft();
115 		String bounds= ""; //$NON-NLS-1$
116 		for (ITypeConstraint constraint : constraints) {
117 			ConstraintVariable right= ((SimpleTypeConstraint) constraint).getRight();
118 			ITypeBinding binding= right.getBinding();
119 			String typeName= binding.getQualifiedName();
120 			bounds= bounds + typeName +","; //$NON-NLS-1$
121 		}
122 
123 		if (fOrConstraints.containsKey(left)){
124 			Map<String, CompositeOrTypeConstraint> m2= fOrConstraints.get(left);
125 			if (m2.containsKey(bounds)){
126 				if (PRINT_STATS) fNrRetrieved++;
127 				if (PRINT_STATS) dumpStats();
128 				return m2.get(bounds);
129 			} else {
130 				CompositeOrTypeConstraint constraint= new CompositeOrTypeConstraint(constraints);
131 				m2.put(bounds, constraint);
132 				if (PRINT_STATS) dumpStats();
133 				if (PRINT_STATS) fNrCreated++;
134 				return constraint;
135 			}
136 		} else {
137 			Map<String, CompositeOrTypeConstraint> m2= new HashMap<>();
138 			fOrConstraints.put(left, m2);
139 			CompositeOrTypeConstraint constraint= new CompositeOrTypeConstraint(constraints);
140 			m2.put(bounds, constraint);
141 			if (PRINT_STATS) dumpStats();
142 			if (PRINT_STATS) fNrCreated++;
143 			return constraint;
144 		}
145 	}
146 
dumpStats()147 	protected void dumpStats() {
148 		System.out.println("Constraints: " + fNrCreated + " created, " + fNrRetrieved + " retrieved, " + fNrFiltered + " filtered");	 //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
149 	}
150 
151 }
152