PageRenderTime 51ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/bundles/org.eclipse.wst.jsdt.ui/src/org/eclipse/wst/jsdt/internal/corext/util/JavaModelUtil.java

https://bitbucket.org/nexj/webtools.jsdt.core
Java | 947 lines | 600 code | 81 blank | 266 comment | 185 complexity | c9eca4b58b146a590c0039907de9213a MD5 | raw file
  1. /*******************************************************************************
  2. * Copyright (c) 2000, 2009 IBM Corporation and others.
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Eclipse Public License v1.0
  5. * which accompanies this distribution, and is available at
  6. * http://www.eclipse.org/legal/epl-v10.html
  7. *
  8. * Contributors:
  9. * IBM Corporation - initial API and implementation
  10. * Matt Chapman, mpchapman@gmail.com - 89977 Make JDT .java agnostic
  11. *******************************************************************************/
  12. package org.eclipse.wst.jsdt.internal.corext.util;
  13. import java.util.Arrays;
  14. import java.util.HashSet;
  15. import java.util.Map;
  16. import org.eclipse.core.filebuffers.FileBuffers;
  17. import org.eclipse.core.filebuffers.ITextFileBufferManager;
  18. import org.eclipse.core.filebuffers.LocationKind;
  19. import org.eclipse.core.resources.IFile;
  20. import org.eclipse.core.resources.IResource;
  21. import org.eclipse.core.resources.IStorage;
  22. import org.eclipse.core.runtime.Assert;
  23. import org.eclipse.core.runtime.CoreException;
  24. import org.eclipse.core.runtime.IPath;
  25. import org.eclipse.core.runtime.IProgressMonitor;
  26. import org.eclipse.core.runtime.IStatus;
  27. import org.eclipse.core.runtime.NullProgressMonitor;
  28. import org.eclipse.core.runtime.Path;
  29. import org.eclipse.core.runtime.SubProgressMonitor;
  30. import org.eclipse.jface.text.BadLocationException;
  31. import org.eclipse.jface.text.Document;
  32. import org.eclipse.jface.text.IDocument;
  33. import org.eclipse.jface.text.RewriteSessionEditProcessor;
  34. import org.eclipse.text.edits.MalformedTreeException;
  35. import org.eclipse.text.edits.TextEdit;
  36. import org.eclipse.wst.jsdt.core.JsGlobalScopeContainerInitializer;
  37. import org.eclipse.wst.jsdt.core.Flags;
  38. import org.eclipse.wst.jsdt.core.IJsGlobalScopeContainer;
  39. import org.eclipse.wst.jsdt.core.IIncludePathEntry;
  40. import org.eclipse.wst.jsdt.core.IJavaScriptUnit;
  41. import org.eclipse.wst.jsdt.core.IField;
  42. import org.eclipse.wst.jsdt.core.IJarEntryResource;
  43. import org.eclipse.wst.jsdt.core.IJavaScriptElement;
  44. import org.eclipse.wst.jsdt.core.IJavaScriptProject;
  45. import org.eclipse.wst.jsdt.core.ILocalVariable;
  46. import org.eclipse.wst.jsdt.core.IMember;
  47. import org.eclipse.wst.jsdt.core.IFunction;
  48. import org.eclipse.wst.jsdt.core.IPackageFragment;
  49. import org.eclipse.wst.jsdt.core.IPackageFragmentRoot;
  50. import org.eclipse.wst.jsdt.core.IType;
  51. import org.eclipse.wst.jsdt.core.ITypeHierarchy;
  52. import org.eclipse.wst.jsdt.core.JavaScriptCore;
  53. import org.eclipse.wst.jsdt.core.JavaScriptModelException;
  54. import org.eclipse.wst.jsdt.core.Signature;
  55. import org.eclipse.wst.jsdt.core.WorkingCopyOwner;
  56. import org.eclipse.wst.jsdt.core.compiler.CharOperation;
  57. import org.eclipse.wst.jsdt.internal.core.util.Util;
  58. import org.eclipse.wst.jsdt.internal.corext.CorextMessages;
  59. import org.eclipse.wst.jsdt.internal.corext.ValidateEditException;
  60. import org.eclipse.wst.jsdt.internal.corext.template.java.SignatureUtil;
  61. import org.eclipse.wst.jsdt.internal.ui.JavaUIStatus;
  62. import org.eclipse.wst.jsdt.launching.IVMInstall;
  63. import org.eclipse.wst.jsdt.launching.IVMInstall2;
  64. import org.eclipse.wst.jsdt.launching.JavaRuntime;
  65. /**
  66. * Utility methods for the Java Model.
  67. */
  68. public final class JavaModelUtil {
  69. /**
  70. * Only use this suffix for creating new .java files.
  71. * In general, use one of the three *JavaLike*(..) methods in JavaScriptCore or create
  72. * a name from an existing compilation unit with {@link #getRenamedCUName(IJavaScriptUnit, String)}
  73. * <p>
  74. * Note: Unlike {@link JavaScriptCore#getJavaScriptLikeExtensions()}, this suffix includes a leading ".".
  75. * </p>
  76. *
  77. * @see JavaScriptCore#getJavaScriptLikeExtensions()
  78. * @see JavaScriptCore#isJavaScriptLikeFileName(String)
  79. * @see JavaScriptCore#removeJavaScriptLikeExtension(String)
  80. * @see #getRenamedCUName(IJavaScriptUnit, String)
  81. */
  82. public static final String DEFAULT_CU_SUFFIX= ".js"; //$NON-NLS-1$
  83. /**
  84. * Finds a type by its qualified type name (dot separated).
  85. * @param jproject The java project to search in
  86. * @param fullyQualifiedName The fully qualified name (type name with enclosing type names and package (all separated by dots))
  87. * @return The type found, or null if not existing
  88. */
  89. public static IType findType(IJavaScriptProject jproject, String fullyQualifiedName) throws JavaScriptModelException {
  90. //workaround for bug 22883
  91. IType type= jproject.findType(fullyQualifiedName);
  92. if (type != null)
  93. return type;
  94. IPackageFragmentRoot[] roots= jproject.getPackageFragmentRoots();
  95. for (int i= 0; i < roots.length; i++) {
  96. IPackageFragmentRoot root= roots[i];
  97. type= findType(root, fullyQualifiedName);
  98. if (type != null && type.exists())
  99. return type;
  100. }
  101. return null;
  102. }
  103. /**
  104. * Finds a type by its qualified type name (dot separated).
  105. * @param jproject The java project to search in
  106. * @param fullyQualifiedName The fully qualified name (type name with enclosing type names and package (all separated by dots))
  107. * @param owner the working copy owner
  108. * @return The type found, or null if not existing
  109. */
  110. public static IType findType(IJavaScriptProject jproject, String fullyQualifiedName, WorkingCopyOwner owner) throws JavaScriptModelException {
  111. //workaround for bug 22883
  112. IType type= jproject.findType(fullyQualifiedName, owner);
  113. if (type != null)
  114. return type;
  115. IPackageFragmentRoot[] roots= jproject.getPackageFragmentRoots();
  116. for (int i= 0; i < roots.length; i++) {
  117. IPackageFragmentRoot root= roots[i];
  118. type= findType(root, fullyQualifiedName);
  119. if (type != null && type.exists())
  120. return type;
  121. }
  122. return null;
  123. }
  124. private static IType findType(IPackageFragmentRoot root, String fullyQualifiedName) throws JavaScriptModelException{
  125. IJavaScriptElement[] children= root.getChildren();
  126. for (int i= 0; i < children.length; i++) {
  127. IJavaScriptElement element= children[i];
  128. if (element.getElementType() == IJavaScriptElement.PACKAGE_FRAGMENT){
  129. IPackageFragment pack= (IPackageFragment)element;
  130. if (! fullyQualifiedName.startsWith(pack.getElementName()))
  131. continue;
  132. IType type= findType(pack, fullyQualifiedName);
  133. if (type != null && type.exists())
  134. return type;
  135. }
  136. }
  137. return null;
  138. }
  139. private static IType findType(IPackageFragment pack, String fullyQualifiedName) throws JavaScriptModelException{
  140. IJavaScriptUnit[] cus= pack.getJavaScriptUnits();
  141. for (int i= 0; i < cus.length; i++) {
  142. IJavaScriptUnit unit= cus[i];
  143. IType type= findType(unit, fullyQualifiedName);
  144. if (type != null && type.exists())
  145. return type;
  146. }
  147. return null;
  148. }
  149. private static IType findType(IJavaScriptUnit cu, String fullyQualifiedName) throws JavaScriptModelException{
  150. IType[] types= cu.getAllTypes();
  151. for (int i= 0; i < types.length; i++) {
  152. IType type= types[i];
  153. if (getFullyQualifiedName(type).equals(fullyQualifiedName))
  154. return type;
  155. }
  156. return null;
  157. }
  158. /**
  159. * Finds a type container by container name.
  160. * The returned element will be of type <code>IType</code> or a <code>IPackageFragment</code>.
  161. * <code>null</code> is returned if the type container could not be found.
  162. * @param jproject The Java project defining the context to search
  163. * @param typeContainerName A dot separated name of the type container
  164. * @see #getTypeContainerName(IType)
  165. */
  166. public static IJavaScriptElement findTypeContainer(IJavaScriptProject jproject, String typeContainerName) throws JavaScriptModelException {
  167. // try to find it as type
  168. IJavaScriptElement result= jproject.findType(typeContainerName);
  169. if (result == null) {
  170. // find it as package
  171. IPath path= new Path(typeContainerName.replace('.', '/'));
  172. result= jproject.findElement(path);
  173. if (!(result instanceof IPackageFragment)) {
  174. result= null;
  175. }
  176. }
  177. return result;
  178. }
  179. /**
  180. * Finds a type in a compilation unit. Typical usage is to find the corresponding
  181. * type in a working copy.
  182. * @param cu the compilation unit to search in
  183. * @param typeQualifiedName the type qualified name (type name with enclosing type names (separated by dots))
  184. * @return the type found, or null if not existing
  185. */
  186. public static IType findTypeInCompilationUnit(IJavaScriptUnit cu, String typeQualifiedName) throws JavaScriptModelException {
  187. IType[] types= cu.getAllTypes();
  188. for (int i= 0; i < types.length; i++) {
  189. String currName= getTypeQualifiedName(types[i]);
  190. if (typeQualifiedName.equals(currName)) {
  191. return types[i];
  192. }
  193. }
  194. return null;
  195. }
  196. /**
  197. * Returns the element of the given compilation unit which is "equal" to the
  198. * given element. Note that the given element usually has a parent different
  199. * from the given compilation unit.
  200. *
  201. * @param cu the cu to search in
  202. * @param element the element to look for
  203. * @return an element of the given cu "equal" to the given element
  204. */
  205. public static IJavaScriptElement findInCompilationUnit(IJavaScriptUnit cu, IJavaScriptElement element) {
  206. IJavaScriptElement[] elements= cu.findElements(element);
  207. if (elements != null && elements.length > 0) {
  208. return elements[0];
  209. }
  210. return null;
  211. }
  212. /**
  213. * Returns the qualified type name of the given type using '.' as separators.
  214. * This is a replace for IType.getTypeQualifiedName()
  215. * which uses '$' as separators. As '$' is also a valid character in an id
  216. * this is ambiguous. JavaScriptCore PR: 1GCFUNT
  217. */
  218. public static String getTypeQualifiedName(IType type) {
  219. try {
  220. if (type.isBinary() && !type.isAnonymous()) {
  221. IType declaringType= type.getDeclaringType();
  222. if (declaringType != null) {
  223. return getTypeQualifiedName(declaringType) + '.' + type.getElementName();
  224. }
  225. }
  226. } catch (JavaScriptModelException e) {
  227. // ignore
  228. }
  229. return type.getTypeQualifiedName('.');
  230. }
  231. /**
  232. * Returns the fully qualified name of the given type using '.' as separators.
  233. * This is a replace for IType.getFullyQualifiedTypeName
  234. * which uses '$' as separators. As '$' is also a valid character in an id
  235. * this is ambiguous. JavaScriptCore PR: 1GCFUNT
  236. */
  237. public static String getFullyQualifiedName(IType type) {
  238. try {
  239. if (type.isBinary() && !type.isAnonymous()) {
  240. IType declaringType= type.getDeclaringType();
  241. if (declaringType != null) {
  242. return getFullyQualifiedName(declaringType) + '.' + type.getElementName();
  243. }
  244. }
  245. } catch (JavaScriptModelException e) {
  246. // ignore
  247. }
  248. return type.getFullyQualifiedName('.');
  249. }
  250. /**
  251. * Returns the fully qualified name of a type's container. (package name or enclosing type name)
  252. */
  253. public static String getTypeContainerName(IType type) {
  254. IType outerType= type.getDeclaringType();
  255. if (outerType != null) {
  256. return getFullyQualifiedName(outerType);
  257. } else {
  258. return type.getPackageFragment().getElementName();
  259. }
  260. }
  261. /**
  262. * Concatenates two names. Uses a dot for separation.
  263. * Both strings can be empty or <code>null</code>.
  264. */
  265. public static String concatenateName(String name1, String name2) {
  266. StringBuffer buf= new StringBuffer();
  267. if (name1 != null && name1.length() > 0) {
  268. buf.append(name1);
  269. }
  270. if (name2 != null && name2.length() > 0) {
  271. if (buf.length() > 0) {
  272. buf.append('.');
  273. }
  274. buf.append(name2);
  275. }
  276. return buf.toString();
  277. }
  278. /**
  279. * Concatenates two names. Uses a dot for separation.
  280. * Both strings can be empty or <code>null</code>.
  281. */
  282. public static String concatenateName(char[] name1, char[] name2) {
  283. StringBuffer buf= new StringBuffer();
  284. if (name1 != null && name1.length > 0) {
  285. buf.append(name1);
  286. }
  287. if (name2 != null && name2.length > 0) {
  288. if (buf.length() > 0) {
  289. buf.append('.');
  290. }
  291. buf.append(name2);
  292. }
  293. return buf.toString();
  294. }
  295. /**
  296. * Evaluates if a member (possible from another package) is visible from
  297. * elements in a package.
  298. * @param member The member to test the visibility for
  299. * @param pack The package in focus
  300. */
  301. public static boolean isVisible(IMember member, IPackageFragment pack) throws JavaScriptModelException {
  302. int type= member.getElementType();
  303. if (type == IJavaScriptElement.INITIALIZER || (type == IJavaScriptElement.METHOD && member.getElementName().startsWith("<"))) { //$NON-NLS-1$
  304. return false;
  305. }
  306. int otherflags= member.getFlags();
  307. if (Flags.isPublic(otherflags)) {
  308. return true;
  309. } else if (Flags.isPrivate(otherflags)) {
  310. return false;
  311. }
  312. IPackageFragment otherpack= (IPackageFragment) member.getAncestor(IJavaScriptElement.PACKAGE_FRAGMENT);
  313. return (pack != null && otherpack != null && isSamePackage(pack, otherpack));
  314. }
  315. /**
  316. * Evaluates if a member in the focus' element hierarchy is visible from
  317. * elements in a package.
  318. * @param member The member to test the visibility for
  319. * @param pack The package of the focus element focus
  320. */
  321. public static boolean isVisibleInHierarchy(IMember member, IPackageFragment pack) throws JavaScriptModelException {
  322. int type= member.getElementType();
  323. if (type == IJavaScriptElement.INITIALIZER || (type == IJavaScriptElement.METHOD && member.getElementName().startsWith("<"))) { //$NON-NLS-1$
  324. return false;
  325. }
  326. return true;
  327. // int otherflags= member.getFlags();
  328. //
  329. // if (Flags.isPublic(otherflags)) {
  330. // return true;
  331. // } else if (Flags.isPrivate(otherflags)) {
  332. // return false;
  333. // }
  334. //
  335. // IPackageFragment otherpack= (IPackageFragment) member.getAncestor(IJavaScriptElement.PACKAGE_FRAGMENT);
  336. // return (pack != null && pack.equals(otherpack));
  337. }
  338. /**
  339. * Returns the package fragment root of <code>IJavaScriptElement</code>. If the given
  340. * element is already a package fragment root, the element itself is returned.
  341. */
  342. public static IPackageFragmentRoot getPackageFragmentRoot(IJavaScriptElement element) {
  343. return (IPackageFragmentRoot) element.getAncestor(IJavaScriptElement.PACKAGE_FRAGMENT_ROOT);
  344. }
  345. /**
  346. * Finds a method in a type.
  347. * This searches for a method with the same name and signature. Parameter types are only
  348. * compared by the simple name, no resolving for the fully qualified type name is done.
  349. * Constructors are only compared by parameters, not the name.
  350. * @param name The name of the method to find
  351. * @param paramTypes The type signatures of the parameters e.g. <code>{"QString;","I"}</code>
  352. * @param isConstructor If the method is a constructor
  353. * @return The first found method or <code>null</code>, if nothing found
  354. */
  355. public static IFunction findMethod(String name, String[] paramTypes, boolean isConstructor, IType type) throws JavaScriptModelException {
  356. IFunction[] methods= type.getFunctions();
  357. for (int i= 0; i < methods.length; i++) {
  358. if (isSameMethodSignature(name, paramTypes, isConstructor, methods[i])) {
  359. return methods[i];
  360. }
  361. }
  362. return null;
  363. }
  364. /**
  365. * Finds a method in a type and all its super types. The super class hierarchy is searched first, then the super interfaces.
  366. * This searches for a method with the same name and signature. Parameter types are only
  367. * compared by the simple name, no resolving for the fully qualified type name is done.
  368. * Constructors are only compared by parameters, not the name.
  369. * NOTE: For finding overridden methods or for finding the declaring method, use {@link MethodOverrideTester}
  370. * @param hierarchy The hierarchy containing the type
  371. * @param type The type to start the search from
  372. * @param name The name of the method to find
  373. * @param paramTypes The type signatures of the parameters e.g. <code>{"QString;","I"}</code>
  374. * @param isConstructor If the method is a constructor
  375. * @return The first found method or <code>null</code>, if nothing found
  376. */
  377. public static IFunction findMethodInHierarchy(ITypeHierarchy hierarchy, IType type, String name, String[] paramTypes, boolean isConstructor) throws JavaScriptModelException {
  378. IFunction method= findMethod(name, paramTypes, isConstructor, type);
  379. if (method != null) {
  380. return method;
  381. }
  382. IType superClass= hierarchy.getSuperclass(type);
  383. if (superClass != null) {
  384. IFunction res= findMethodInHierarchy(hierarchy, superClass, name, paramTypes, isConstructor);
  385. if (res != null) {
  386. return res;
  387. }
  388. }
  389. return method;
  390. }
  391. /**
  392. * Tests if a method equals to the given signature.
  393. * Parameter types are only compared by the simple name, no resolving for
  394. * the fully qualified type name is done. Constructors are only compared by
  395. * parameters, not the name.
  396. * @param name Name of the method
  397. * @param paramTypes The type signatures of the parameters e.g. <code>{"QString;","I"}</code>
  398. * @param isConstructor Specifies if the method is a constructor
  399. * @return Returns <code>true</code> if the method has the given name and parameter types and constructor state.
  400. */
  401. public static boolean isSameMethodSignature(String name, String[] paramTypes, boolean isConstructor, IFunction curr) throws JavaScriptModelException {
  402. if (isConstructor || name.equals(curr.getElementName())) {
  403. if (isConstructor == curr.isConstructor()) {
  404. String[] currParamTypes= curr.getParameterTypes();
  405. if (paramTypes.length == currParamTypes.length) {
  406. for (int i= 0; i < paramTypes.length; i++) {
  407. String t1= Signature.getSimpleName(Signature.toString(paramTypes[i]));
  408. String t2= Signature.getSimpleName(Signature.toString(currParamTypes[i]));
  409. if (!t1.equals(t2)) {
  410. return false;
  411. }
  412. }
  413. return true;
  414. }
  415. }
  416. }
  417. return false;
  418. }
  419. /**
  420. * Tests if two <code>IPackageFragment</code>s represent the same logical java package.
  421. * @return <code>true</code> if the package fragments' names are equal.
  422. */
  423. public static boolean isSamePackage(IPackageFragment pack1, IPackageFragment pack2) {
  424. return pack1.getElementName().equals(pack2.getElementName());
  425. }
  426. /**
  427. * Checks if the field is boolean.
  428. */
  429. public static boolean isBoolean(IField field) throws JavaScriptModelException{
  430. return field.getTypeSignature().equals(SignatureUtil.BOOLEAN_SIGNATURE);
  431. }
  432. /**
  433. * Resolves a type name in the context of the declaring type.
  434. *
  435. * @param refTypeSig the type name in signature notation (for example 'QVector') this can also be an array type, but dimensions will be ignored.
  436. * @param declaringType the context for resolving (type where the reference was made in)
  437. * @return returns the fully qualified type name or build-in-type name. if a unresolved type couldn't be resolved null is returned
  438. */
  439. public static String getResolvedTypeName(String refTypeSig, IType declaringType) throws JavaScriptModelException {
  440. int arrayCount= Signature.getArrayCount(refTypeSig);
  441. char type= refTypeSig.charAt(arrayCount);
  442. if (type == Signature.C_UNRESOLVED) {
  443. String name= ""; //$NON-NLS-1$
  444. int semi= refTypeSig.indexOf(Signature.C_SEMICOLON, arrayCount + 1);
  445. if (semi == -1) {
  446. throw new IllegalArgumentException();
  447. }
  448. name= refTypeSig.substring(arrayCount + 1, semi);
  449. String[][] resolvedNames= declaringType.resolveType(name);
  450. if (resolvedNames != null && resolvedNames.length > 0) {
  451. return JavaModelUtil.concatenateName(resolvedNames[0][0], resolvedNames[0][1]);
  452. }
  453. return null;
  454. } else {
  455. return Signature.toString(refTypeSig.substring(arrayCount));
  456. }
  457. }
  458. /**
  459. * Returns if a CU can be edited.
  460. */
  461. public static boolean isEditable(IJavaScriptUnit cu) {
  462. Assert.isNotNull(cu);
  463. IResource resource= cu.getPrimary().getResource();
  464. return (resource.exists() && !resource.getResourceAttributes().isReadOnly());
  465. }
  466. /**
  467. * Returns true if a cu is a primary cu (original or shared working copy)
  468. */
  469. public static boolean isPrimary(IJavaScriptUnit cu) {
  470. return cu.getOwner() == null;
  471. }
  472. /*
  473. * http://bugs.eclipse.org/bugs/show_bug.cgi?id=19253
  474. *
  475. * Reconciling happens in a separate thread. This can cause a situation where the
  476. * Java element gets disposed after an exists test has been done. So we should not
  477. * log not present exceptions when they happen in working copies.
  478. */
  479. public static boolean isExceptionToBeLogged(CoreException exception) {
  480. if (!(exception instanceof JavaScriptModelException))
  481. return true;
  482. JavaScriptModelException je= (JavaScriptModelException)exception;
  483. if (!je.isDoesNotExist())
  484. return true;
  485. IJavaScriptElement[] elements= je.getJavaScriptModelStatus().getElements();
  486. for (int i= 0; i < elements.length; i++) {
  487. IJavaScriptElement element= elements[i];
  488. // if the element is already a compilation unit don't log
  489. // does not exist exceptions. See bug
  490. // https://bugs.eclipse.org/bugs/show_bug.cgi?id=75894
  491. // for more details
  492. if (element.getElementType() == IJavaScriptElement.JAVASCRIPT_UNIT)
  493. continue;
  494. IJavaScriptUnit unit= (IJavaScriptUnit)element.getAncestor(IJavaScriptElement.JAVASCRIPT_UNIT);
  495. if (unit == null)
  496. return true;
  497. if (!unit.isWorkingCopy())
  498. return true;
  499. }
  500. return false;
  501. }
  502. public static IType[] getAllSuperTypes(IType type, IProgressMonitor pm) throws JavaScriptModelException {
  503. // workaround for 23656
  504. IType[] superTypes= SuperTypeHierarchyCache.getTypeHierarchy(type).getAllSuperclasses(type);
  505. return superTypes;
  506. }
  507. public static boolean isSuperType(ITypeHierarchy hierarchy, IType possibleSuperType, IType type) {
  508. // filed bug 112635 to add this method to ITypeHierarchy
  509. IType superClass= hierarchy.getSuperclass(type);
  510. if (superClass != null && (possibleSuperType.equals(superClass) || isSuperType(hierarchy, possibleSuperType, superClass))) {
  511. return true;
  512. }
  513. return false;
  514. }
  515. public static boolean isExcludedPath(IPath resourcePath, IPath[] exclusionPatterns) {
  516. char[] path = resourcePath.toString().toCharArray();
  517. for (int i = 0, length = exclusionPatterns.length; i < length; i++) {
  518. char[] pattern= exclusionPatterns[i].toString().toCharArray();
  519. if (CharOperation.pathMatch(pattern, path, true, '/')) {
  520. return true;
  521. }
  522. }
  523. return false;
  524. }
  525. /*
  526. * Returns whether the given resource path matches one of the exclusion
  527. * patterns.
  528. *
  529. * @see IIncludePathEntry#getExclusionPatterns
  530. */
  531. public final static boolean isExcluded(IPath resourcePath, char[][] exclusionPatterns) {
  532. if (exclusionPatterns == null) return false;
  533. char[] path = resourcePath.toString().toCharArray();
  534. for (int i = 0, length = exclusionPatterns.length; i < length; i++)
  535. if (CharOperation.pathMatch(exclusionPatterns[i], path, true, '/'))
  536. return true;
  537. return false;
  538. }
  539. /**
  540. * Force a reconcile of a compilation unit.
  541. * @param unit
  542. */
  543. public static void reconcile(IJavaScriptUnit unit) throws JavaScriptModelException {
  544. unit.reconcile(
  545. IJavaScriptUnit.NO_AST,
  546. false /* don't force problem detection */,
  547. null /* use primary owner */,
  548. null /* no progress monitor */);
  549. }
  550. /**
  551. * Helper method that tests if an classpath entry can be found in a
  552. * container. <code>null</code> is returned if the entry can not be found
  553. * or if the container does not allows the configuration of source
  554. * attachments
  555. * @param jproject The container's parent project
  556. * @param containerPath The path of the container
  557. * @param libPath The path of the library to be found
  558. * @return IIncludePathEntry A classpath entry from the container of
  559. * <code>null</code> if the container can not be modified.
  560. * @throws JavaScriptModelException thrown if accessing the container failed
  561. */
  562. public static IIncludePathEntry getClasspathEntryToEdit(IJavaScriptProject jproject, IPath containerPath, IPath libPath) throws JavaScriptModelException {
  563. IJsGlobalScopeContainer container= JavaScriptCore.getJsGlobalScopeContainer(containerPath, jproject);
  564. JsGlobalScopeContainerInitializer initializer= JavaScriptCore.getJsGlobalScopeContainerInitializer(containerPath.segment(0));
  565. if (container != null && initializer != null && initializer.canUpdateJsGlobalScopeContainer(containerPath, jproject)) {
  566. return findEntryInContainer(container, libPath);
  567. }
  568. return null; // attachment not possible
  569. }
  570. /**
  571. * Finds an entry in a container. <code>null</code> is returned if the entry can not be found
  572. * @param container The container
  573. * @param libPath The path of the library to be found
  574. * @return IIncludePathEntry A classpath entry from the container of
  575. * <code>null</code> if the container can not be modified.
  576. */
  577. public static IIncludePathEntry findEntryInContainer(IJsGlobalScopeContainer container, IPath libPath) {
  578. IIncludePathEntry[] entries= container.getIncludepathEntries();
  579. for (int i= 0; i < entries.length; i++) {
  580. IIncludePathEntry curr= entries[i];
  581. IIncludePathEntry resolved= JavaScriptCore.getResolvedIncludepathEntry(curr);
  582. if (resolved != null && libPath.equals(resolved.getPath())) {
  583. return curr; // return the real entry
  584. }
  585. }
  586. return null; // attachment not possible
  587. }
  588. /**
  589. * Get all compilation units of a selection.
  590. * @param javaElements the selected java elements
  591. * @return all compilation units containing and contained in elements from javaElements
  592. * @throws JavaScriptModelException
  593. */
  594. public static IJavaScriptUnit[] getAllCompilationUnits(IJavaScriptElement[] javaElements) throws JavaScriptModelException {
  595. HashSet result= new HashSet();
  596. for (int i= 0; i < javaElements.length; i++) {
  597. addAllCus(result, javaElements[i]);
  598. }
  599. return (IJavaScriptUnit[]) result.toArray(new IJavaScriptUnit[result.size()]);
  600. }
  601. private static void addAllCus(HashSet/*<IJavaScriptUnit>*/ collector, IJavaScriptElement javaElement) throws JavaScriptModelException {
  602. switch (javaElement.getElementType()) {
  603. case IJavaScriptElement.JAVASCRIPT_PROJECT:
  604. IJavaScriptProject javaProject= (IJavaScriptProject) javaElement;
  605. IPackageFragmentRoot[] packageFragmentRoots= javaProject.getPackageFragmentRoots();
  606. for (int i= 0; i < packageFragmentRoots.length; i++)
  607. addAllCus(collector, packageFragmentRoots[i]);
  608. return;
  609. case IJavaScriptElement.PACKAGE_FRAGMENT_ROOT:
  610. IPackageFragmentRoot packageFragmentRoot= (IPackageFragmentRoot) javaElement;
  611. if (packageFragmentRoot.getKind() != IPackageFragmentRoot.K_SOURCE)
  612. return;
  613. IJavaScriptElement[] packageFragments= packageFragmentRoot.getChildren();
  614. for (int j= 0; j < packageFragments.length; j++)
  615. addAllCus(collector, packageFragments[j]);
  616. return;
  617. case IJavaScriptElement.PACKAGE_FRAGMENT:
  618. IPackageFragment packageFragment= (IPackageFragment) javaElement;
  619. collector.addAll(Arrays.asList(packageFragment.getJavaScriptUnits()));
  620. return;
  621. case IJavaScriptElement.JAVASCRIPT_UNIT:
  622. collector.add(javaElement);
  623. return;
  624. default:
  625. IJavaScriptElement cu= javaElement.getAncestor(IJavaScriptElement.JAVASCRIPT_UNIT);
  626. if (cu != null)
  627. collector.add(cu);
  628. }
  629. }
  630. /**
  631. * Sets all compliance settings in the given map to 5.0
  632. */
  633. public static void set50CompilanceOptions(Map map) {
  634. setCompilanceOptions(map, JavaScriptCore.VERSION_1_5);
  635. }
  636. public static void setCompilanceOptions(Map map, String compliance) {
  637. if (JavaScriptCore.VERSION_1_6.equals(compliance)) {
  638. map.put(JavaScriptCore.COMPILER_COMPLIANCE, JavaScriptCore.VERSION_1_6);
  639. map.put(JavaScriptCore.COMPILER_SOURCE, JavaScriptCore.VERSION_1_6);
  640. map.put(JavaScriptCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaScriptCore.VERSION_1_6);
  641. map.put(JavaScriptCore.COMPILER_PB_ASSERT_IDENTIFIER, JavaScriptCore.ERROR);
  642. } else if (JavaScriptCore.VERSION_1_5.equals(compliance)) {
  643. map.put(JavaScriptCore.COMPILER_COMPLIANCE, JavaScriptCore.VERSION_1_5);
  644. map.put(JavaScriptCore.COMPILER_SOURCE, JavaScriptCore.VERSION_1_5);
  645. map.put(JavaScriptCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaScriptCore.VERSION_1_5);
  646. map.put(JavaScriptCore.COMPILER_PB_ASSERT_IDENTIFIER, JavaScriptCore.ERROR);
  647. } else if (JavaScriptCore.VERSION_1_4.equals(compliance)) {
  648. map.put(JavaScriptCore.COMPILER_COMPLIANCE, JavaScriptCore.VERSION_1_4);
  649. map.put(JavaScriptCore.COMPILER_SOURCE, JavaScriptCore.VERSION_1_3);
  650. map.put(JavaScriptCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaScriptCore.VERSION_1_2);
  651. map.put(JavaScriptCore.COMPILER_PB_ASSERT_IDENTIFIER, JavaScriptCore.WARNING);
  652. } else if (JavaScriptCore.VERSION_1_3.equals(compliance)) {
  653. map.put(JavaScriptCore.COMPILER_COMPLIANCE, JavaScriptCore.VERSION_1_3);
  654. map.put(JavaScriptCore.COMPILER_SOURCE, JavaScriptCore.VERSION_1_3);
  655. map.put(JavaScriptCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaScriptCore.VERSION_1_1);
  656. map.put(JavaScriptCore.COMPILER_PB_ASSERT_IDENTIFIER, JavaScriptCore.IGNORE);
  657. } else {
  658. throw new IllegalArgumentException("Unsupported compliance: " + compliance); //$NON-NLS-1$
  659. }
  660. }
  661. public static void setDefaultClassfileOptions(Map map, String compliance) {
  662. map.put(JavaScriptCore.COMPILER_CODEGEN_INLINE_JSR_BYTECODE, is50OrHigher(compliance) ? JavaScriptCore.ENABLED : JavaScriptCore.DISABLED);
  663. map.put(JavaScriptCore.COMPILER_LOCAL_VARIABLE_ATTR, JavaScriptCore.GENERATE);
  664. map.put(JavaScriptCore.COMPILER_LINE_NUMBER_ATTR, JavaScriptCore.GENERATE);
  665. map.put(JavaScriptCore.COMPILER_SOURCE_FILE_ATTR, JavaScriptCore.GENERATE);
  666. map.put(JavaScriptCore.COMPILER_CODEGEN_UNUSED_LOCAL, JavaScriptCore.PRESERVE);
  667. }
  668. /**
  669. * @return returns if version 1 is less than version 2.
  670. */
  671. public static boolean isVersionLessThan(String version1, String version2) {
  672. return version1.compareTo(version2) < 0;
  673. }
  674. public static boolean is50OrHigher(String compliance) {
  675. return !isVersionLessThan(compliance, JavaScriptCore.VERSION_1_5);
  676. }
  677. public static boolean is50OrHigher(IJavaScriptProject project) {
  678. return is50OrHigher(project.getOption(JavaScriptCore.COMPILER_COMPLIANCE, true));
  679. }
  680. public static boolean is50OrHigherJRE(IJavaScriptProject project) throws CoreException {
  681. IVMInstall vmInstall= JavaRuntime.getVMInstall(project);
  682. if (!(vmInstall instanceof IVMInstall2))
  683. return true; // assume 5.0.
  684. String compliance= getCompilerCompliance((IVMInstall2) vmInstall, null);
  685. if (compliance == null)
  686. return true; // assume 5.0
  687. return compliance.startsWith(JavaScriptCore.VERSION_1_5) || compliance.startsWith(JavaScriptCore.VERSION_1_6);
  688. }
  689. public static String getCompilerCompliance(IVMInstall2 vMInstall, String defaultCompliance) {
  690. String version= vMInstall.getJavaVersion();
  691. if (version == null) {
  692. return defaultCompliance;
  693. } else if (version.startsWith(JavaScriptCore.VERSION_1_6)) {
  694. return JavaScriptCore.VERSION_1_6;
  695. } else if (version.startsWith(JavaScriptCore.VERSION_1_5)) {
  696. return JavaScriptCore.VERSION_1_5;
  697. } else if (version.startsWith(JavaScriptCore.VERSION_1_4)) {
  698. return JavaScriptCore.VERSION_1_4;
  699. } else if (version.startsWith(JavaScriptCore.VERSION_1_3)) {
  700. return JavaScriptCore.VERSION_1_3;
  701. } else if (version.startsWith(JavaScriptCore.VERSION_1_2)) {
  702. return JavaScriptCore.VERSION_1_3;
  703. } else if (version.startsWith(JavaScriptCore.VERSION_1_1)) {
  704. return JavaScriptCore.VERSION_1_3;
  705. }
  706. return defaultCompliance;
  707. }
  708. // public static String getExecutionEnvironmentCompliance(IExecutionEnvironment executionEnvironment) {
  709. // String desc= executionEnvironment.getId();
  710. // if (desc.indexOf("1.6") != -1) { //$NON-NLS-1$
  711. // return JavaScriptCore.VERSION_1_6;
  712. // } else if (desc.indexOf("1.5") != -1) { //$NON-NLS-1$
  713. // return JavaScriptCore.VERSION_1_5;
  714. // } else if (desc.indexOf("1.4") != -1) { //$NON-NLS-1$
  715. // return JavaScriptCore.VERSION_1_4;
  716. // }
  717. // return JavaScriptCore.VERSION_1_3;
  718. // }
  719. /**
  720. * Compute a new name for a compilation unit, given the name of the new main type.
  721. * This query tries to maintain the existing extension (e.g. ".java").
  722. *
  723. * @param cu a compilation unit
  724. * @param newMainName the new name of the cu's main type (without extension)
  725. * @return the new name for the compilation unit
  726. */
  727. public static String getRenamedCUName(IJavaScriptUnit cu, String newMainName) {
  728. String oldName = cu.getElementName();
  729. int i = oldName.lastIndexOf('.');
  730. if (i != -1) {
  731. return newMainName + oldName.substring(i);
  732. } else {
  733. return newMainName;
  734. }
  735. }
  736. /**
  737. * Applies an text edit to a compilation unit. Filed bug 117694 against jdt.core.
  738. * @param cu the compilation unit to apply the edit to
  739. * @param edit the edit to apply
  740. * @param save is set, save the CU after the edit has been applied
  741. * @param monitor the progress monitor to use
  742. * @throws CoreException Thrown when the access to the CU failed
  743. * @throws ValidateEditException if validate edit fails
  744. */
  745. public static void applyEdit(IJavaScriptUnit cu, TextEdit edit, boolean save, IProgressMonitor monitor) throws CoreException, ValidateEditException {
  746. if (monitor == null) {
  747. monitor= new NullProgressMonitor();
  748. }
  749. monitor.beginTask(CorextMessages.JavaModelUtil_applyedit_operation, 3);
  750. try {
  751. IDocument document= null;
  752. try {
  753. document= aquireDocument(cu, new SubProgressMonitor(monitor, 1));
  754. if (save) {
  755. commitDocument(cu, document, edit, new SubProgressMonitor(monitor, 1));
  756. } else {
  757. new RewriteSessionEditProcessor(document, edit, TextEdit.UPDATE_REGIONS).performEdits();
  758. }
  759. } catch (BadLocationException e) {
  760. throw new CoreException(JavaUIStatus.createError(IStatus.ERROR, e));
  761. } finally {
  762. releaseDocument(cu, document, new SubProgressMonitor(monitor, 1));
  763. }
  764. } finally {
  765. monitor.done();
  766. }
  767. }
  768. private static IDocument aquireDocument(IJavaScriptUnit cu, IProgressMonitor monitor) throws CoreException {
  769. if (JavaModelUtil.isPrimary(cu)) {
  770. IFile file= (IFile) cu.getResource();
  771. if (file.exists()) {
  772. ITextFileBufferManager bufferManager= FileBuffers.getTextFileBufferManager();
  773. IPath path= cu.getPath();
  774. bufferManager.connect(path, LocationKind.IFILE, monitor);
  775. return bufferManager.getTextFileBuffer(path, LocationKind.IFILE).getDocument();
  776. }
  777. }
  778. monitor.done();
  779. return new Document(cu.getSource());
  780. }
  781. private static void commitDocument(IJavaScriptUnit cu, IDocument document, TextEdit edit, IProgressMonitor monitor) throws CoreException, MalformedTreeException, BadLocationException {
  782. if (JavaModelUtil.isPrimary(cu)) {
  783. IFile file= (IFile) cu.getResource();
  784. if (file.exists()) {
  785. IStatus status= Resources.makeCommittable(file, null);
  786. if (!status.isOK()) {
  787. throw new ValidateEditException(status);
  788. }
  789. new RewriteSessionEditProcessor(document, edit, TextEdit.UPDATE_REGIONS).performEdits(); // apply after file is commitable
  790. ITextFileBufferManager bufferManager= FileBuffers.getTextFileBufferManager();
  791. bufferManager.getTextFileBuffer(file.getFullPath(), LocationKind.IFILE).commit(monitor, true);
  792. return;
  793. }
  794. }
  795. // no commit possible, make sure changes are in
  796. new RewriteSessionEditProcessor(document, edit, TextEdit.UPDATE_REGIONS).performEdits();
  797. }
  798. private static void releaseDocument(IJavaScriptUnit cu, IDocument document, IProgressMonitor monitor) throws CoreException {
  799. if (JavaModelUtil.isPrimary(cu)) {
  800. IFile file= (IFile) cu.getResource();
  801. if (file.exists()) {
  802. ITextFileBufferManager bufferManager= FileBuffers.getTextFileBufferManager();
  803. bufferManager.disconnect(file.getFullPath(), LocationKind.IFILE, monitor);
  804. return;
  805. }
  806. }
  807. cu.getBuffer().setContents(document.get());
  808. monitor.done();
  809. }
  810. public static boolean isImplicitImport(String qualifier, IJavaScriptUnit cu) {
  811. if ("java.lang".equals(qualifier)) { //$NON-NLS-1$
  812. return true;
  813. }
  814. String packageName= cu.getParent().getElementName();
  815. if (qualifier.equals(packageName)) {
  816. return true;
  817. }
  818. String typeName= JavaScriptCore.removeJavaScriptLikeExtension(cu.getElementName());
  819. String mainTypeName= JavaModelUtil.concatenateName(packageName, typeName);
  820. return qualifier.equals(mainTypeName);
  821. }
  822. public static boolean isOpenableStorage(Object storage) {
  823. if (storage instanceof IJarEntryResource) {
  824. return ((IJarEntryResource) storage).isFile();
  825. } else {
  826. return storage instanceof IStorage;
  827. }
  828. }
  829. /**
  830. * Returns true iff the given local variable is a parameter of its
  831. * declaring method.
  832. *
  833. * TODO replace this method with new API when available:
  834. * https://bugs.eclipse.org/bugs/show_bug.cgi?id=48420
  835. * @param currentLocal the local variable to test
  836. *
  837. * @return returns true if the variable is a parameter
  838. * @throws JavaScriptModelException
  839. */
  840. public static boolean isParameter(ILocalVariable currentLocal) throws JavaScriptModelException {
  841. final IJavaScriptElement parent= currentLocal.getParent();
  842. if (parent instanceof IFunction) {
  843. final String[] params= ((IFunction) parent).getParameterNames();
  844. for (int i= 0; i < params.length; i++) {
  845. if (params[i].equals(currentLocal.getElementName()))
  846. return true;
  847. }
  848. }
  849. return false;
  850. }
  851. public static String getFilePackage(IJavaScriptElement javaElement)
  852. {
  853. IJavaScriptElement fileAncestor = javaElement.getAncestor(IJavaScriptElement.JAVASCRIPT_UNIT);
  854. if (fileAncestor==null)
  855. fileAncestor=javaElement.getAncestor(IJavaScriptElement.CLASS_FILE);
  856. IPath filePath= fileAncestor.getResource().getFullPath();
  857. IJavaScriptElement rootElement=fileAncestor.getAncestor(IJavaScriptElement.PACKAGE_FRAGMENT_ROOT);
  858. IPath rootPath = rootElement.getResource().getFullPath();
  859. String relativePath = filePath.removeFirstSegments(rootPath.segmentCount()).toPortableString();
  860. int index=Util.indexOfJavaLikeExtension(relativePath);
  861. if (index>=0)
  862. relativePath=relativePath.substring(0,index);
  863. relativePath=relativePath.replace('/', '.');
  864. return relativePath;
  865. }
  866. }