bitbucket-20: adding conditions for enclosing class/package (transplanting from trunk).
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
6 * The contents of this file are subject to the terms of either the GNU
7 * General Public License Version 2 only ("GPL") or the Common
8 * Development and Distribution License("CDDL") (collectively, the
9 * "License"). You may not use this file except in compliance with the
10 * License. You can obtain a copy of the License at
11 * http://www.netbeans.org/cddl-gplv2.html
12 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13 * specific language governing permissions and limitations under the
14 * License. When distributing the software, include this License Header
15 * Notice in each file and include the License file at
16 * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
17 * particular file as subject to the "Classpath" exception as provided
18 * by Sun in the GPL Version 2 section of the License file that
19 * accompanied this code. If applicable, add the following below the
20 * License Header, with the fields enclosed by brackets [] replaced by
21 * your own identifying information:
22 * "Portions Copyrighted [year] [name of copyright owner]"
24 * If you wish your version of this file to be governed by only the CDDL
25 * or only the GPL Version 2, indicate your decision by adding
26 * "[Contributor] elects to include this software in this distribution
27 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28 * single choice of license, a recipient has the option to distribute
29 * your version of this file under either the CDDL, the GPL Version 2 or
30 * to extend the choice of license to its licensees as provided above.
31 * However, if you add GPL Version 2 code and therefore, elected the GPL
32 * Version 2 license, then the option applies only if the new code is
33 * made subject to such option by the copyright holder.
37 * Portions Copyrighted 2009 Sun Microsystems, Inc.
40 package org.netbeans.modules.jackpot30.file.conditionapi;
42 import com.sun.source.tree.CompilationUnitTree;
43 import com.sun.source.tree.Tree.Kind;
44 import com.sun.source.util.TreePath;
45 import java.util.ArrayList;
46 import java.util.Collection;
47 import java.util.Collections;
48 import java.util.EnumSet;
49 import java.util.HashMap;
50 import java.util.LinkedList;
51 import java.util.List;
54 import java.util.concurrent.atomic.AtomicInteger;
55 import javax.lang.model.SourceVersion;
56 import javax.lang.model.element.Element;
57 import javax.lang.model.element.ElementKind;
58 import javax.lang.model.element.Modifier;
59 import javax.lang.model.element.TypeElement;
60 import javax.lang.model.type.TypeKind;
61 import javax.lang.model.type.TypeMirror;
62 import org.netbeans.api.annotations.common.CheckForNull;
63 import org.netbeans.api.annotations.common.NonNull;
64 import org.netbeans.api.java.queries.SourceLevelQuery;
65 import org.netbeans.api.java.source.TreeUtilities;
66 import org.netbeans.modules.jackpot30.file.APIAccessor;
67 import org.netbeans.modules.jackpot30.spi.Hacks;
68 import org.netbeans.modules.jackpot30.spi.HintContext;
74 public class Context {
76 final HintContext ctx;
77 final List<Map<String, TreePath>> variables = new LinkedList<Map<String, TreePath>>();
78 final List<Map<String, Collection<? extends TreePath>>> multiVariables = new LinkedList<Map<String, Collection<? extends TreePath>>>();
79 final List<Map<String, String>> variableNames = new LinkedList<Map<String, String>>();
80 private final AtomicInteger auxiliaryVariableCounter = new AtomicInteger();
82 //XXX: should not be public:
83 public Context(HintContext ctx) {
85 this.variables.add(Collections.unmodifiableMap(ctx.getVariables()));
86 this.multiVariables.add(Collections.unmodifiableMap(ctx.getMultiVariables()));
87 this.variableNames.add(Collections.unmodifiableMap(ctx.getVariableNames()));
90 public @NonNull SourceVersion sourceVersion() {
91 String sourceLevel = SourceLevelQuery.getSourceLevel(ctx.getInfo().getFileObject());
93 if (sourceLevel == null) {
94 return SourceVersion.latest(); //TODO
97 String[] splited = sourceLevel.split("\\.");
98 String spec = splited[1];
100 return SourceVersion.valueOf("RELEASE_"+ spec);//!!!
103 public @NonNull Set<Modifier> modifiers(@NonNull Variable variable) {
104 final Element e = ctx.getInfo().getTrees().getElement(getSingleVariable(variable));
107 return Collections.unmodifiableSet(EnumSet.noneOf(Modifier.class));
110 return Collections.unmodifiableSet(e.getModifiers());
113 public @CheckForNull ElementKind elementKind(@NonNull Variable variable) {
114 final Element e = ctx.getInfo().getTrees().getElement(getSingleVariable(variable));
123 public @CheckForNull TypeKind typeKind(@NonNull Variable variable) {
124 final TypeMirror tm = ctx.getInfo().getTrees().getTypeMirror(getSingleVariable(variable));
133 public @CheckForNull String name(@NonNull Variable variable) {
134 final Element e = ctx.getInfo().getTrees().getElement(getSingleVariable(variable));
140 return e.getSimpleName().toString();
143 public @CheckForNull Variable parent(@NonNull Variable variable) {
144 TreePath tp = getSingleVariable(variable);
146 if (tp.getParentPath() == null) {
150 return enterAuxiliaryVariable(tp.getParentPath());
153 private Variable enterAuxiliaryVariable(TreePath path) {
154 String output = "*" + auxiliaryVariableCounter.getAndIncrement();
156 variables.get(0).put(output, path);
158 return new Variable(output);
161 public @NonNull Variable variableForName(@NonNull String variableName) {
162 Variable result = new Variable(variableName);
164 if (getSingleVariable(result) == null) {
165 throw new IllegalStateException("Unknown variable");
171 public void createRenamed(@NonNull Variable from, @NonNull Variable to, @NonNull String newName) {
172 //TODO: check (the variable should not exist)
173 variableNames.get(0).put(to.variableName, newName);
174 TreePath origVariablePath = getSingleVariable(from);
175 TreePath newVariablePath = new TreePath(origVariablePath.getParentPath(), Hacks.createRenameTree(origVariablePath.getLeaf(), newName));
176 variables.get(0).put(to.variableName, newVariablePath);
179 public boolean isNullLiteral(@NonNull Variable var) {
180 TreePath varPath = getSingleVariable(var);
182 return varPath.getLeaf().getKind() == Kind.NULL_LITERAL;
185 public @NonNull Iterable<? extends Variable> getIndexedVariables(@NonNull Variable multiVariable) {
186 Iterable<? extends TreePath> paths = getMultiVariable(multiVariable);
189 throw new IllegalArgumentException("TODO: explanation");
192 Collection<Variable> result = new LinkedList<Variable>();
195 for (TreePath tp : paths) {
196 result.add(new Variable(multiVariable.variableName, index++));
202 public void enterScope() {
203 variables.add(0, new HashMap<String, TreePath>());
204 multiVariables.add(0, new HashMap<String, Collection<? extends TreePath>>());
205 variableNames.add(0, new HashMap<String, String>());
208 public void leaveScope() {
210 multiVariables.remove(0);
211 variableNames.remove(0);
214 Iterable<? extends TreePath> getVariable(Variable v) {
215 if (isMultistatementWildcard(v.variableName) && v.index == (-1)) {
216 return getMultiVariable(v);
218 return Collections.singletonList(getSingleVariable(v));
222 //XXX: copied from jackpot30.impl.Utilities:
223 private static boolean isMultistatementWildcard(/*@NonNull */CharSequence name) {
224 return name.charAt(name.length() - 1) == '$';
227 //TODO: check if correct variable is provided:
228 TreePath getSingleVariable(Variable v) {
229 if (v.index == (-1)) {
230 for (Map<String, TreePath> map : variables) {
231 if (map.containsKey(v.variableName)) {
232 return map.get(v.variableName);
238 return new ArrayList<TreePath>(getMultiVariable(v)).get(v.index);
242 private Collection<? extends TreePath> getMultiVariable(Variable v) {
243 for (Map<String, Collection<? extends TreePath>> multi : multiVariables) {
244 if (multi.containsKey(v.variableName)) {
245 return multi.get(v.variableName);
253 APIAccessor.IMPL = new APIAccessorImpl();
256 /**Returns canonical names of classes that enclose the {@link Variable}.
257 * If the given {@link Variable} represents a class, its canonical name is also listed.
258 * The names are given from the innermost class to the outermost class.
260 * @return the canonical names of the enclosing classes
262 public @NonNull Iterable<? extends String> enclosingClasses(Variable forVariable) {
263 List<String> result = new ArrayList<String>();
264 TreePath path = getSingleVariable(forVariable);
266 while (path != null) {
267 TreePath current = path;
269 path = path.getParentPath();
271 if (!TreeUtilities.CLASS_TREE_KINDS.contains(current.getLeaf().getKind())) continue;
273 Element e = ctx.getInfo().getTrees().getElement(current);
275 if (e == null) continue;
277 if (e.getKind().isClass() || e.getKind().isInterface()) {
278 result.add(((TypeElement) e).getQualifiedName().toString());
285 /**Returns name of package in which the current file is located. Default package
286 * is represented by an empty string.
288 * @return the name of the enclosing package
290 public @NonNull String enclosingPackage() {
291 CompilationUnitTree cut = ctx.getInfo().getCompilationUnit();
293 return cut.getPackageName() != null ? cut.getPackageName().toString() : "";
296 static final class APIAccessorImpl extends APIAccessor {
299 public TreePath getSingleVariable(Context ctx, Variable var) {
300 return ctx.getSingleVariable(var);
304 public HintContext getHintContext(Context ctx) {
309 public Map<String, TreePath> getVariables(Context ctx) {
310 Map<String, TreePath> result = new HashMap<String, TreePath>();
312 for (Map<String, TreePath> m : reverse(ctx.variables)) {
320 public Map<String, Collection<? extends TreePath>> getMultiVariables(Context ctx) {
321 Map<String, Collection<? extends TreePath>> result = new HashMap<String, Collection<? extends TreePath>>();
323 for (Map<String, Collection<? extends TreePath>> m : reverse(ctx.multiVariables)) {
331 public Map<String, String> getVariableNames(Context ctx) {
332 Map<String, String> result = new HashMap<String, String>();
334 for (Map<String, String> m : reverse(ctx.variableNames)) {
341 private <T> List<T> reverse(List<T> original) {
342 List<T> result = new LinkedList<T>();
344 for (T t : original) {
352 public Variable enterAuxiliaryVariable(Context ctx, TreePath source) {
353 return ctx.enterAuxiliaryVariable(source);