/******************************************************************************* * Copyright (c) 2017 Alex Xu and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Alex Xu - initial API and implementation *******************************************************************************/ package org.eclipse.php.internal.core.ast.rewrite; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.core.resources.ProjectScope; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.preferences.IScopeContext; import org.eclipse.core.runtime.preferences.InstanceScope; import org.eclipse.dltk.core.IBuffer; import org.eclipse.dltk.core.IScriptProject; import org.eclipse.dltk.core.ISourceModule; import org.eclipse.dltk.core.ModelException; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.Region; import org.eclipse.php.core.ast.nodes.*; import org.eclipse.php.core.compiler.ast.nodes.NamespaceReference; import org.eclipse.php.internal.core.typeinference.PHPModelUtils; import org.eclipse.text.edits.DeleteEdit; import org.eclipse.text.edits.InsertEdit; import org.eclipse.text.edits.MultiTextEdit; public final class ImportRewriteAnalyzer { private final ISourceModule sourceModule; private final List<NamespaceDeclaration> namespaces; private final Map<NamespaceDeclaration, ArrayList<PackageEntry>> packageEntries; private final Map<NamespaceDeclaration, List<String>> importsCreated; private final Map<NamespaceDeclaration, IRegion> replaceRange; private boolean filterImplicitImports; private Map<NamespaceDeclaration, Integer> flags = new HashMap<>(); private static final int F_NEEDS_LEADING_DELIM = 2; private static final int F_NEEDS_TRAILING_DELIM = 4; public ImportRewriteAnalyzer(ISourceModule sourceModule, Program root, String[] importOrder, Map<NamespaceDeclaration, Boolean> restoreExistingImports) { this.sourceModule = sourceModule; this.filterImplicitImports = true; this.packageEntries = new HashMap<>(); this.importsCreated = new HashMap<>(); this.replaceRange = new HashMap<>(); this.namespaces = root.getNamespaceDeclarations(); if (this.namespaces.size() > 0) { for (NamespaceDeclaration namespace : this.namespaces) { initialize(root, namespace, importOrder, restoreExistingImports); } } else { initialize(root, null, importOrder, restoreExistingImports); } } private void initialize(Program root, NamespaceDeclaration namespace, String[] importOrder, Map<NamespaceDeclaration, Boolean> restoreExistingImports) { this.packageEntries.put(namespace, new ArrayList<>(20)); this.importsCreated.put(namespace, new ArrayList<>()); this.flags.put(namespace, 0); this.replaceRange.put(namespace, evaluateReplaceRange(root, namespace)); if (restoreExistingImports.get(namespace)) { addExistingImports(root, namespace); } PackageEntry[] order = new PackageEntry[importOrder.length]; for (int i = 0; i < order.length; i++) { String curr = importOrder[i]; order[i] = new PackageEntry(curr, curr); // normal import group } addPreferenceOrderHolders(this.packageEntries.get(namespace), order); } private void addPreferenceOrderHolders(ArrayList<PackageEntry> packageEntries, PackageEntry[] preferenceOrder) { if (packageEntries.isEmpty()) { // all new: copy the elements for (int i = 0; i < preferenceOrder.length; i++) { packageEntries.add(preferenceOrder[i]); } } else { // match the preference order entries to existing imports // entries not found are appended after the last successfully // matched entry PackageEntry[] lastAssigned = new PackageEntry[preferenceOrder.length]; // find an existing package entry that matches most for (int k = 0; k < packageEntries.size(); k++) { PackageEntry entry = packageEntries.get(k); if (!entry.isComment()) { String currName = entry.getName(); int currNameLen = currName.length(); int bestGroupIndex = -1; int bestGroupLen = -1; for (int i = 0; i < preferenceOrder.length; i++) { String currPrefEntry = preferenceOrder[i].getName(); int currPrefLen = currPrefEntry.length(); if (currName.startsWith(currPrefEntry) && currPrefLen >= bestGroupLen) { if (currPrefLen == currNameLen || currName.charAt(currPrefLen) == NamespaceReference.NAMESPACE_SEPARATOR) { if (bestGroupIndex == -1 || currPrefLen > bestGroupLen) { bestGroupLen = currPrefLen; bestGroupIndex = i; } } } } if (bestGroupIndex != -1) { entry.setGroupID(preferenceOrder[bestGroupIndex].getName()); lastAssigned[bestGroupIndex] = entry; // remember last // entry } } } // fill in not-assigned categories, keep partial order int currAppendIndex = 0; for (int i = 0; i < lastAssigned.length; i++) { PackageEntry entry = lastAssigned[i]; if (entry == null) { PackageEntry newEntry = preferenceOrder[i]; if (currAppendIndex == 0) { currAppendIndex = getIndexAfterStatics(packageEntries); } packageEntries.add(currAppendIndex, newEntry); currAppendIndex++; } else { currAppendIndex = packageEntries.indexOf(entry) + 1; } } } } private static String getQualifier(String decl) { String namesapceName = PHPModelUtils.extractNameSpaceName(decl); if (namesapceName == null) { return "global namespace"; //$NON-NLS-1$ } return namesapceName; } private static String getFullName(UseStatement decl) { if (decl.parts().get(0).getAlias() != null) { return decl.parts().get(0).getAlias().getName(); } return decl.parts().get(0).getName().getName(); } private void addExistingImports(Program root, NamespaceDeclaration namespace) { List<UseStatement> decls = root.getUseStatements(namespace); if (decls.isEmpty()) { return; } PackageEntry currPackage = null; UseStatement curr = decls.get(0); int currOffset = curr.getStart(); int currLength = curr.getLength(); int currEndLine = root.getLineNumber(currOffset + currLength); for (int i = 1; i < decls.size(); i++) { String name = getFullName(curr); String packName = getQualifier(name); if (currPackage == null || currPackage.compareTo(packName) != 0) { currPackage = new PackageEntry(packName, null); this.packageEntries.get(namespace).add(currPackage); } UseStatement next = decls.get(i); int nextOffset = next.getStart(); int nextLength = next.getLength(); int nextOffsetLine = root.getLineNumber(nextOffset + 1); // if next import is on a different line, modify the end position to // the next line begin offset if (currEndLine < nextOffsetLine) { currEndLine++; nextOffset = getPostion(root, currEndLine); } currPackage.add(new ImportDeclEntry(name, new Region(currOffset, nextOffset - currOffset))); currOffset = nextOffset; curr = next; // add a comment entry for spacing between imports if (currEndLine < nextOffsetLine) { nextOffset = getPostion(root, nextOffsetLine); currPackage = new PackageEntry(); // create a comment package // entry for this this.packageEntries.get(namespace).add(currPackage); currPackage.add(new ImportDeclEntry(null, new Region(currOffset, nextOffset - currOffset))); currOffset = nextOffset; } currEndLine = root.getLineNumber(nextOffset + nextLength); } String name = getFullName(curr); String packName = getQualifier(name); if (currPackage == null || currPackage.compareTo(packName) != 0) { currPackage = new PackageEntry(packName, null); this.packageEntries.get(namespace).add(currPackage); } int length = this.replaceRange.get(namespace).getOffset() + this.replaceRange.get(namespace).getLength() - curr.getStart(); currPackage.add(new ImportDeclEntry(name, new Region(curr.getStart(), length))); } /** * Sets that implicit imports (types in default package, CU- package and * 'java.lang') should not be created. Note that this is a heuristic filter * and can lead to missing imports, e.g. in cases where a type is forced to * be specified due to a name conflict. By default, the filter is enabled. * * @param filterImplicitImports * The filterImplicitImports to set */ public void setFilterImplicitImports(boolean filterImplicitImports) { this.filterImplicitImports = filterImplicitImports; } private static class PackageMatcher { private String newName; private String bestName; private int bestMatchLen; public PackageMatcher() { // initialization in 'initialize' } public void initialize(String newImportName, String bestImportName) { this.newName = newImportName; this.bestName = bestImportName; this.bestMatchLen = getCommonPrefixLength(bestImportName, newImportName); } public boolean isBetterMatch(String currName, boolean preferCurr) { boolean isBetter; int currMatchLen = getCommonPrefixLength(currName, this.newName); int matchDiff = currMatchLen - this.bestMatchLen; if (matchDiff == 0) { if (currMatchLen == this.newName.length() && currMatchLen == currName.length() && currMatchLen == this.bestName.length()) { // duplicate entry and complete match isBetter = preferCurr; } else { isBetter = sameMatchLenTest(currName); } } else { isBetter = (matchDiff > 0); // curr has longer match } if (isBetter) { this.bestName = currName; this.bestMatchLen = currMatchLen; } return isBetter; } private boolean sameMatchLenTest(String currName) { int matchLen = this.bestMatchLen; // known: bestName and currName differ from newName at position // 'matchLen' // currName and bestName don't have to differ at position 'matchLen' // determine the order and return true if currName is closer to // newName char newChar = getCharAt(this.newName, matchLen); char currChar = getCharAt(currName, matchLen); char bestChar = getCharAt(this.bestName, matchLen); if (newChar < currChar) { if (bestChar < newChar) { // b < n < c return (currChar - newChar) < (newChar - bestChar); // -> (c // - n) // < (n // - b) } else { // n < b && n < c if (currChar == bestChar) { // longer match between curr and // best return false; // keep curr and best together, new should // be before both } else { return currChar < bestChar; // -> (c < b) } } } else { if (bestChar > newChar) { // c < n < b return (newChar - currChar) < (bestChar - newChar); // -> (n // - c) // < (b // - n) } else { // n > b && n > c if (currChar == bestChar) { // longer match between curr and // best return true; // keep curr and best together, new should // be ahead of both } else { return currChar > bestChar; // -> (c > b) } } } } } /* package */static int getCommonPrefixLength(String s, String t) { int len = Math.min(s.length(), t.length()); for (int i = 0; i < len; i++) { if (s.charAt(i) != t.charAt(i)) { return i; } } return len; } /* package */static char getCharAt(String str, int index) { if (str.length() > index) { return str.charAt(index); } return 0; } private PackageEntry findBestMatch(ArrayList<PackageEntry> packageEntries, String newName, boolean isStatic) { if (packageEntries.isEmpty()) { return null; } String groupId = null; int longestPrefix = -1; // find the matching group for (int i = 0; i < packageEntries.size(); i++) { PackageEntry curr = packageEntries.get(i); String currGroup = curr.getGroupID(); if (currGroup != null && newName.startsWith(currGroup)) { int prefixLen = currGroup.length(); if (prefixLen == newName.length()) { return curr; // perfect fit, use entry } if ((newName.charAt(prefixLen) == NamespaceReference.NAMESPACE_SEPARATOR || prefixLen == 0) && prefixLen > longestPrefix) { longestPrefix = prefixLen; groupId = currGroup; } } } PackageEntry bestMatch = null; PackageMatcher matcher = new PackageMatcher(); matcher.initialize(newName, ""); //$NON-NLS-1$ for (int i = 0; i < packageEntries.size(); i++) { // find the best // match with // the same // group PackageEntry curr = packageEntries.get(i); if (!curr.isComment()) { if (groupId == null || groupId.equals(curr.getGroupID())) { boolean preferrCurr = (bestMatch == null) || (curr.getNumberOfImports() > bestMatch.getNumberOfImports()); if (matcher.isBetterMatch(curr.getName(), preferrCurr)) { bestMatch = curr; } } } } return bestMatch; } private boolean isImplicitImport(NamespaceDeclaration namespace, String qualifier) { String packageName; if (namespace == null) { packageName = "global namespace"; //$NON-NLS-1$ } else { packageName = namespace.getName().getName(); } if (qualifier.equals(packageName)) { return true; } return false; } public void addImport(NamespaceDeclaration namespace, String fullTypeName, boolean isStatic) { String typeContainerName = getQualifier(fullTypeName); ImportDeclEntry decl = new ImportDeclEntry(fullTypeName, null); sortIn(this.packageEntries.get(namespace), typeContainerName, decl, isStatic); } public boolean removeImport(NamespaceDeclaration namespace, String qualifiedName) { String containerName = getQualifier(qualifiedName); int nPackages = this.packageEntries.get(namespace).size(); for (int i = 0; i < nPackages; i++) { PackageEntry entry = this.packageEntries.get(namespace).get(i); if (entry.compareTo(containerName) == 0) { if (entry.remove(qualifiedName)) { return true; } } } return false; } private int getIndexAfterStatics(ArrayList<PackageEntry> packageEntries) { return packageEntries.size(); } private void sortIn(ArrayList<PackageEntry> packageEntries, String typeContainerName, ImportDeclEntry decl, boolean isStatic) { PackageEntry bestMatch = findBestMatch(packageEntries, typeContainerName, isStatic); if (bestMatch == null) { PackageEntry packEntry = new PackageEntry(typeContainerName, null); packEntry.add(decl); int insertPos = getIndexAfterStatics(packageEntries); packageEntries.add(insertPos, packEntry); } else { int cmp = typeContainerName.compareTo(bestMatch.getName()); if (cmp == 0) { bestMatch.sortIn(decl); } else { // create a new package entry String group = bestMatch.getGroupID(); if (group != null) { if (!typeContainerName.startsWith(group)) { group = null; } } PackageEntry packEntry = new PackageEntry(typeContainerName, group); packEntry.add(decl); int index = packageEntries.indexOf(bestMatch); if (cmp < 0) { // insert ahead of best match packageEntries.add(index, packEntry); } else { // insert after best match packageEntries.add(index + 1, packEntry); } } } } private IRegion evaluateReplaceRange(Program root, NamespaceDeclaration namespace) { List<UseStatement> imports = root.getUseStatements(namespace); if (!imports.isEmpty()) { UseStatement first = imports.get(0); UseStatement last = imports.get(imports.size() - 1); int startPos = first.getStart(); int endPos = root.getExtendedStartPosition(last) + root.getExtendedLength(last); int endLine = root.getLineNumber(endPos); if (endLine > 0) { int nextLinePos = getPostion(root, endLine + 1); if (nextLinePos >= 0) { int firstStatementPos = getFirstStatementBeginPos(root, namespace); if (firstStatementPos != -1 && firstStatementPos < nextLinePos) { endPos = firstStatementPos; } else { endPos = nextLinePos; } } } return new Region(startPos, endPos - startPos); } else { int start = getNamespaceNameEndPos(root, namespace); return new Region(start, 0); } } public MultiTextEdit getResultingEdits(IProgressMonitor monitor) throws ModelException { if (monitor == null) { monitor = new NullProgressMonitor(); } MultiTextEdit resEdit = new MultiTextEdit(); if (namespaces.size() > 0) { for (NamespaceDeclaration namespace : namespaces) { getResultingEdits(namespace, resEdit, monitor); } } else { getResultingEdits(null, resEdit, monitor); } return resEdit; } private void getResultingEdits(NamespaceDeclaration namespace, MultiTextEdit resEdit, IProgressMonitor monitor) throws ModelException { try { int importsStart = this.replaceRange.get(namespace).getOffset(); int importsLen = this.replaceRange.get(namespace).getLength(); String lineDelim = getLineDelimiterUsed(sourceModule.getScriptProject()); IBuffer buffer = this.sourceModule.getBuffer(); int currPos = importsStart; if ((this.flags.get(namespace) & F_NEEDS_LEADING_DELIM) != 0) { // new import container resEdit.addChild(new InsertEdit(currPos, lineDelim)); } ArrayList<String> stringsToInsert = new ArrayList<String>(); int nPackageEntries = this.packageEntries.get(namespace).size(); for (int i = 0; i < nPackageEntries; i++) { PackageEntry pack = this.packageEntries.get(namespace).get(i); int nImports = pack.getNumberOfImports(); if (this.filterImplicitImports && isImplicitImport(namespace, pack.getName())) { pack.removeAllNew(); nImports = pack.getNumberOfImports(); } if (nImports == 0) { continue; } for (int k = 0; k < nImports; k++) { ImportDeclEntry currDecl = pack.getImportAt(k); IRegion region = currDecl.getSourceRange(); if (region == null) { // new entry String str = getNewImportString(namespace, currDecl.getElementName(), lineDelim); stringsToInsert.add(str); } else { int offset = region.getOffset(); removeAndInsertNew(buffer, currPos, offset, stringsToInsert, resEdit); stringsToInsert.clear(); currPos = offset + region.getLength(); } } } int end = importsStart + importsLen; removeAndInsertNew(buffer, currPos, end, stringsToInsert, resEdit); if (importsLen == 0) { if (!this.importsCreated.get(namespace).isEmpty()) { // new // import // container if ((this.flags.get(namespace) & F_NEEDS_TRAILING_DELIM) != 0) { resEdit.addChild(new InsertEdit(currPos, lineDelim)); } } else if (resEdit.getChildrenSize() > 0) { resEdit.removeChild(resEdit.getChildrenSize() - 1); } } } finally { monitor.done(); } } private void removeAndInsertNew(IBuffer buffer, int contentOffset, int contentEnd, ArrayList<String> stringsToInsert, MultiTextEdit resEdit) { int pos = contentOffset; for (int i = 0; i < stringsToInsert.size(); i++) { String curr = stringsToInsert.get(i); int idx = findInBuffer(buffer, curr, pos, contentEnd); if (idx != -1) { if (idx != pos) { resEdit.addChild(new DeleteEdit(pos, idx - pos)); } pos = idx + curr.length(); } else { resEdit.addChild(new InsertEdit(pos, curr)); } } if (pos < contentEnd) { resEdit.addChild(new DeleteEdit(pos, contentEnd - pos)); } } private int findInBuffer(IBuffer buffer, String str, int start, int end) { int pos = start; int len = str.length(); if (pos + len > end || str.length() == 0) { return -1; } char first = str.charAt(0); int step = str.indexOf(first, 1); if (step == -1) { step = len; } while (pos + len <= end) { if (buffer.getChar(pos) == first) { int k = 1; while (k < len && buffer.getChar(pos + k) == str.charAt(k)) { k++; } if (k == len) { return pos; // found } if (k < step) { pos += k; } else { pos += step; } } else { pos++; } } return -1; } private String getNewImportString(NamespaceDeclaration namespace, String importName, String lineDelim) { StringBuilder buf = new StringBuilder(); buf.append("use "); //$NON-NLS-1$ buf.append(importName); buf.append(';'); // $NON-NLS-1$ buf.append(lineDelim); this.importsCreated.get(namespace).add(importName); return buf.toString(); } private int getFirstStatementBeginPos(Program root, NamespaceDeclaration namespace) { List<Statement> statements; if (namespace == null) { statements = root.statements(); } else { statements = namespace.getBody().statements(); } if (!statements.isEmpty()) { ASTNode node = null; boolean isAfterUseStatements = false; if (root.getUseStatements(namespace).size() == 0) { isAfterUseStatements = true; } for (Statement s : statements) { if (s instanceof UseStatement) { isAfterUseStatements = true; continue; } if (isAfterUseStatements) { node = s; break; } } if (node != null) { return root.getExtendedStartPosition(node); } } return -1; } private int getNamespaceNameEndPos(Program root, NamespaceDeclaration namespace) { int flags = this.flags.get(namespace); if (namespace != null) { NamespaceName packDecl = namespace.getName(); int afterPackageStatementPos = -1; int lineNumber = root.getLineNumber(packDecl.getStart() + packDecl.getLength()); if (lineNumber >= 0) { int lineAfterPackage = lineNumber + 1; afterPackageStatementPos = getPostion(root, lineAfterPackage); } if (afterPackageStatementPos < 0) { flags |= F_NEEDS_LEADING_DELIM; this.flags.put(namespace, flags); return packDecl.getStart() + packDecl.getLength(); } int firstStatementPos = getFirstStatementBeginPos(root, namespace); if (firstStatementPos != -1 && firstStatementPos <= afterPackageStatementPos) { if (firstStatementPos <= afterPackageStatementPos) { flags |= F_NEEDS_TRAILING_DELIM; if (firstStatementPos == afterPackageStatementPos) { flags |= F_NEEDS_LEADING_DELIM; } this.flags.put(namespace, flags); return firstStatementPos; } } flags |= F_NEEDS_LEADING_DELIM; this.flags.put(namespace, flags); return afterPackageStatementPos; // insert a line after after // package statement } flags |= F_NEEDS_TRAILING_DELIM; this.flags.put(namespace, flags); return getPostion(root, 2); } private int getPostion(Program root, int line) { return getPostion(root, line, 0); } private int getPostion(Program root, int line, int column) { return root.getPosition(line, column) - 1; } public String toString() { StringBuilder buf = new StringBuilder("\n-----------------------\n"); //$NON-NLS-1$ if (namespaces.size() > 0) { for (NamespaceDeclaration namespace : namespaces) { int nPackages = this.packageEntries.get(namespace).size(); for (int i = 0; i < nPackages; i++) { PackageEntry entry = this.packageEntries.get(namespace).get(i); buf.append(entry.toString()); } } } else { int nPackages = this.packageEntries.get(null).size(); for (int i = 0; i < nPackages; i++) { PackageEntry entry = this.packageEntries.get(null).get(i); buf.append(entry.toString()); } } return buf.toString(); } private static final class ImportDeclEntry { private String elementName; private boolean isAlias; private IRegion sourceRange; public ImportDeclEntry(String elementName, IRegion sourceRange) { this.elementName = elementName; if (elementName.toLowerCase().contains(" as ")) { //$NON-NLS-1$ isAlias = true; } this.sourceRange = sourceRange; } public String getElementName() { return this.elementName; } public int compareTo(String fullName) { return this.elementName.compareTo(fullName); } public String getSimpleName() { return PHPModelUtils.extractElementName(elementName); } public boolean isNew() { return this.sourceRange == null; } public boolean isComment() { return this.elementName == null; } public boolean isAlias() { return isAlias; } public IRegion getSourceRange() { return this.sourceRange; } } /* * Internal element for the import structure: A container for imports of all * types from the same package */ private final static class PackageEntry { private String name; private ArrayList<ImportDeclEntry> importEntries; private String group; /** * Comment package entry */ public PackageEntry() { this("!", null); //$NON-NLS-1$ } /** * @param name * Name of the package entry. e.g. org.eclipse.jdt.ui, * containing imports like org.eclipse.jdt.ui.JavaUI. * @param group * The index of the preference order entry assigned different * group id's will result in spacers between the entries */ public PackageEntry(String name, String group) { this.name = name; this.importEntries = new ArrayList<>(5); this.group = group; } public int compareTo(String otherName) { return this.name.compareTo(otherName); } public void sortIn(ImportDeclEntry imp) { String fullImportName = imp.getElementName(); int insertPosition = -1; int nInports = this.importEntries.size(); for (int i = 0; i < nInports; i++) { ImportDeclEntry curr = getImportAt(i); if (!curr.isComment()) { int cmp = curr.compareTo(fullImportName); if (cmp == 0) { return; // exists already } else if (cmp > 0 && insertPosition == -1) { insertPosition = i; } } } if (insertPosition == -1) { this.importEntries.add(imp); } else { this.importEntries.add(insertPosition, imp); } } public void add(ImportDeclEntry imp) { this.importEntries.add(imp); } public boolean remove(String fullName) { int nInports = this.importEntries.size(); for (int i = 0; i < nInports; i++) { ImportDeclEntry curr = getImportAt(i); if (!curr.isComment() && curr.compareTo(fullName) == 0) { this.importEntries.remove(i); return true; } } return false; } public void removeAllNew() { int nInports = this.importEntries.size(); for (int i = nInports - 1; i >= 0; i--) { ImportDeclEntry curr = getImportAt(i); if (!curr.isAlias() && curr.isNew()) { this.importEntries.remove(i); } } } public ImportDeclEntry getImportAt(int index) { return this.importEntries.get(index); } public int getNumberOfImports() { return this.importEntries.size(); } public String getName() { return this.name; } public String getGroupID() { return this.group; } public void setGroupID(String groupID) { this.group = groupID; } public boolean isComment() { return "!".equals(this.name); //$NON-NLS-1$ } public String toString() { StringBuilder buf = new StringBuilder(); if (isComment()) { buf.append("comment\n"); //$NON-NLS-1$ } else { buf.append(this.name); buf.append(", groupId: "); //$NON-NLS-1$ buf.append(this.group); buf.append("\n"); //$NON-NLS-1$ int nImports = getNumberOfImports(); for (int i = 0; i < nImports; i++) { ImportDeclEntry curr = getImportAt(i); buf.append(" "); //$NON-NLS-1$ buf.append(curr.getSimpleName()); if (curr.isNew()) { buf.append(" (new)"); //$NON-NLS-1$ } buf.append("\n"); //$NON-NLS-1$ } } return buf.toString(); } } public String[] getCreatedImports() { List<String> imports = new ArrayList<>(); if (namespaces.size() > 0) { for (NamespaceDeclaration namespace : namespaces) { imports.addAll(this.importsCreated.get(namespace)); } } else { imports.addAll(this.importsCreated.get(null)); } return imports.toArray(new String[imports.size()]); } /** * Returns the line delimiter which is used in the specified project. * * @param project * the java project, or <code>null</code> * @return the used line delimiter */ private static String getLineDelimiterUsed(IScriptProject project) { return getProjectLineDelimiter(project); } private static String getProjectLineDelimiter(IScriptProject project) { if (project == null) { assert false; return null; } String lineDelimiter = getLineDelimiterPreference(project); if (lineDelimiter != null) return lineDelimiter; return System.getProperty("line.separator", "\n"); //$NON-NLS-1$ //$NON-NLS-2$ } private static String getLineDelimiterPreference(IScriptProject project) { IScopeContext[] scopeContext; if (project != null) { // project preference scopeContext = new IScopeContext[] { new ProjectScope(project.getProject()) }; String lineDelimiter = Platform.getPreferencesService().getString(Platform.PI_RUNTIME, Platform.PREF_LINE_SEPARATOR, null, scopeContext); if (lineDelimiter != null) return lineDelimiter; } // workspace preference scopeContext = new IScopeContext[] { InstanceScope.INSTANCE }; String platformDefault = System.getProperty("line.separator", "\n"); //$NON-NLS-1$ //$NON-NLS-2$ return Platform.getPreferencesService().getString(Platform.PI_RUNTIME, Platform.PREF_LINE_SEPARATOR, platformDefault, scopeContext); } }