001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.visualweb.insync.java;
043:
044: import com.sun.source.tree.AssignmentTree;
045: import com.sun.source.tree.ExpressionTree;
046: import com.sun.source.tree.LiteralTree;
047: import com.sun.source.tree.MemberSelectTree;
048: import com.sun.source.tree.MethodInvocationTree;
049: import com.sun.source.tree.NewArrayTree;
050: import com.sun.source.tree.NewClassTree;
051: import com.sun.source.tree.Tree;
052: import com.sun.source.tree.TypeCastTree;
053: import java.lang.reflect.Array;
054: import java.lang.reflect.Field;
055: import java.lang.reflect.Modifier;
056: import java.util.List;
057: import javax.lang.model.element.Element;
058: import javax.lang.model.element.ExecutableElement;
059: import javax.lang.model.element.VariableElement;
060: import org.netbeans.api.java.source.CompilationInfo;
061:
062: /**
063: *
064: * @author jdeva
065: */
066: public class ExpressionUtils {
067: /*
068: * Checks if the expression is a literal
069: */
070: private static boolean isLiteral(ExpressionTree exprTree) {
071: Tree.Kind kind = exprTree.getKind();
072: if (kind == kind.BOOLEAN_LITERAL || kind == kind.CHAR_LITERAL
073: || kind == kind.DOUBLE_LITERAL
074: || kind == kind.FLOAT_LITERAL
075: || kind == kind.INT_LITERAL
076: || kind == kind.LONG_LITERAL
077: || kind == kind.NULL_LITERAL
078: || kind == kind.STRING_LITERAL) {
079: return true;
080: }
081: return false;
082: }
083:
084: /*
085: * Evaluates expression if it is one of the following
086: * a) LiteralTree
087: * b) MethodInvocationTree - only if the method is static
088: * c) NewClassTree
089: * d) NewArrayTree
090: *
091: */
092: public static Object getValue(CompilationInfo cinfo,
093: ExpressionTree valueExpr) {
094: Object value = null;
095: try {
096: if (isLiteral(valueExpr)) {
097: value = ((LiteralTree) valueExpr).getValue();
098: } else if (valueExpr.getKind() == Tree.Kind.MEMBER_SELECT) {
099: //Handles static field access in expression
100: MemberSelectTree memSelTree = (MemberSelectTree) valueExpr;
101: Object object = null;
102: Class cls = null;
103: if (memSelTree.getExpression().getKind() != Tree.Kind.MEMBER_SELECT) {
104: //Ex: new Color(0,0,0).
105: object = getValue(cinfo, memSelTree.getExpression());
106: if (object != null) {
107: cls = object.getClass();
108: }
109: } else {
110: //Ex: Color.BLACK.
111: try {
112: cls = getClass(cinfo, memSelTree
113: .getExpression());
114: } catch (ClassNotFoundException cnfe) {
115: object = getValue(cinfo, memSelTree
116: .getExpression());
117: if (object != null) {
118: cls = object.getClass();
119: }
120: }
121: }
122: if (cls != null) {
123: Field f = cls.getField(memSelTree.getIdentifier()
124: .toString());
125: if (f != null
126: && (object != null || (f.getModifiers() & Modifier.STATIC) > 0)) {
127: value = f.get(object);
128: }
129: }
130: return value;
131: } else if (valueExpr.getKind() == Tree.Kind.METHOD_INVOCATION) {
132: MethodInvocationTree mInvoke = (MethodInvocationTree) valueExpr;
133: ExpressionTree selectTree = mInvoke.getMethodSelect();
134: if (selectTree.getKind() != Tree.Kind.MEMBER_SELECT) {
135: return null;
136: }
137: MemberSelectTree memSelTree = (MemberSelectTree) selectTree;
138: String mname = memSelTree.getIdentifier().toString();
139:
140: List<? extends ExpressionTree> params = mInvoke
141: .getArguments();
142: int count = params.size();
143: Object[] argv = new Object[count];
144: Class[] argvt = new Class[count];
145: Class cls = null;
146: java.lang.reflect.Method m = null;
147: String cname = null;
148:
149: Element elem = cinfo.getTrees()
150: .getElement(
151: cinfo.getTrees().getPath(
152: cinfo.getCompilationUnit(),
153: memSelTree));
154: Object object = null;
155: if (elem instanceof ExecutableElement) {
156: //Check for static field access(ex: Color.BLACK.toString())
157: object = getValue(cinfo, memSelTree.getExpression());
158: if (object != null) {
159: cls = object.getClass();
160: } else {
161: cls = getClass(cinfo, memSelTree
162: .getExpression());
163: }
164: if (cls != null) {
165: ExecutableElement execElem = (ExecutableElement) elem;
166: List<? extends VariableElement> actualParams = execElem
167: .getParameters();
168: for (int i = 0; i < count; i++) {
169: ExpressionTree arg = (ExpressionTree) params
170: .get(i);
171: argv[i] = getValue(cinfo, arg);
172: argvt[i] = ClassUtil.getClass(actualParams
173: .get(i).asType().toString());
174: }
175: m = cls.getMethod(mname, argvt);
176: }
177: }
178: if (m != null
179: && (object != null || (m.getModifiers() & Modifier.STATIC) > 0)) {
180: value = m.invoke(object, argv);
181: }
182: } else if (valueExpr instanceof NewClassTree) {
183: NewClassTree newClassTree = (NewClassTree) valueExpr;
184: Class cls = getClass(cinfo, newClassTree
185: .getIdentifier());
186: if (cls == null) {
187: return null;
188: }
189:
190: List<? extends ExpressionTree> params = newClassTree
191: .getArguments();
192: int count = params.size();
193: Object[] argv = new Object[count];
194: Class[] argvt = new Class[count];
195: java.lang.reflect.Constructor ctor = null;
196: Element elem = cinfo.getTrees().getElement(
197: cinfo.getTrees().getPath(
198: cinfo.getCompilationUnit(),
199: newClassTree));
200: if (elem instanceof ExecutableElement) {
201: ExecutableElement ctorElem = (ExecutableElement) elem;
202: List<? extends VariableElement> actualParams = ctorElem
203: .getParameters();
204: for (int i = 0; i < count; i++) {
205: ExpressionTree arg = (ExpressionTree) params
206: .get(i);
207: argv[i] = getValue(cinfo, arg);
208: argvt[i] = ClassUtil.getClass(actualParams.get(
209: i).asType().toString());
210: }
211: ctor = cls.getConstructor(argvt);
212: }
213: if (ctor != null) {
214: value = ctor.newInstance(argv);
215: }
216: } else if (valueExpr instanceof NewArrayTree) {
217: NewArrayTree newArrayTree = (NewArrayTree) valueExpr;
218: List<? extends ExpressionTree> inits = newArrayTree
219: .getInitializers();
220: int count = inits.size();
221: Class elemClass = getClass(cinfo, newArrayTree
222: .getType());
223: Object array = Array.newInstance(elemClass, count);
224: for (int i = 0; i < count; i++) {
225: ExpressionTree elem = (ExpressionTree) inits.get(i);
226: Array.set(array, i, getValue(cinfo, elem));
227: }
228: value = array;
229:
230: } else if (valueExpr instanceof TypeCastTree) {
231: value = getValue(cinfo, ((TypeCastTree) valueExpr)
232: .getExpression());
233: } else if (valueExpr instanceof AssignmentTree) {
234: value = getValue(cinfo, ((AssignmentTree) valueExpr)
235: .getExpression());
236: }
237: } catch (Exception e) {
238: System.out
239: .println("ExpressinUtils.getValue() " + valueExpr);
240: //Ignore exception and return null
241: }
242:
243: return value;
244: }
245:
246: /*
247: * Internal utility method to obtain a class given the type tree
248: */
249: private static Class getClass(CompilationInfo cinfo, Tree tree)
250: throws ClassNotFoundException {
251: String typeName = TreeUtils.getFQN(cinfo, tree);
252: return ClassUtil.getClass(typeName);
253: }
254:
255: public static String getArgumentSource(CompilationInfo cinfo,
256: ExpressionTree exprTree) {
257: long end = cinfo.getTrees().getSourcePositions()
258: .getEndPosition(cinfo.getCompilationUnit(), exprTree);
259: long start = cinfo.getTrees().getSourcePositions()
260: .getStartPosition(cinfo.getCompilationUnit(), exprTree);
261: return cinfo.getText().substring((int) start, (int) end);
262: }
263: }
|