001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.core;
011:
012: import java.util.Map;
013:
014: import org.eclipse.jdt.core.Flags;
015: import org.eclipse.jdt.core.IJavaProject;
016: import org.eclipse.jdt.core.compiler.CharOperation;
017: import org.eclipse.jdt.core.compiler.InvalidInputException;
018: import org.eclipse.jdt.internal.codeassist.impl.AssistOptions;
019: import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
020: import org.eclipse.jdt.internal.compiler.parser.Scanner;
021: import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
022: import org.eclipse.jdt.internal.compiler.parser.TerminalTokens;
023: import org.eclipse.jdt.internal.compiler.util.SimpleSetOfCharArray;
024:
025: public class InternalNamingConventions {
026: private static final char[] DEFAULT_NAME = "name".toCharArray(); //$NON-NLS-1$
027:
028: private static Scanner getNameScanner(
029: CompilerOptions compilerOptions) {
030: return new Scanner(false /*comment*/, false /*whitespace*/,
031: false /*nls*/,
032: compilerOptions.sourceLevel /*sourceLevel*/,
033: null /*taskTags*/, null/*taskPriorities*/, true/*taskCaseSensitive*/);
034: }
035:
036: public static void suggestArgumentNames(IJavaProject javaProject,
037: char[] packageName, char[] qualifiedTypeName, int dim,
038: char[] internalPrefix, char[][] excludedNames,
039: INamingRequestor requestor) {
040: Map options = javaProject.getOptions(true);
041: CompilerOptions compilerOptions = new CompilerOptions(options);
042: AssistOptions assistOptions = new AssistOptions(options);
043:
044: suggestNames(packageName, qualifiedTypeName, dim,
045: internalPrefix, assistOptions.argumentPrefixes,
046: assistOptions.argumentSuffixes, excludedNames,
047: getNameScanner(compilerOptions), requestor);
048: }
049:
050: public static void suggestFieldNames(IJavaProject javaProject,
051: char[] packageName, char[] qualifiedTypeName, int dim,
052: int modifiers, char[] internalPrefix,
053: char[][] excludedNames, INamingRequestor requestor) {
054: boolean isStatic = Flags.isStatic(modifiers);
055:
056: Map options = javaProject.getOptions(true);
057: CompilerOptions compilerOptions = new CompilerOptions(options);
058: AssistOptions assistOptions = new AssistOptions(options);
059:
060: suggestNames(packageName, qualifiedTypeName, dim,
061: internalPrefix,
062: isStatic ? assistOptions.staticFieldPrefixes
063: : assistOptions.fieldPrefixes,
064: isStatic ? assistOptions.staticFieldSuffixes
065: : assistOptions.fieldSuffixes, excludedNames,
066: getNameScanner(compilerOptions), requestor);
067: }
068:
069: public static void suggestLocalVariableNames(
070: IJavaProject javaProject, char[] packageName,
071: char[] qualifiedTypeName, int dim, char[] internalPrefix,
072: char[][] excludedNames, INamingRequestor requestor) {
073: Map options = javaProject.getOptions(true);
074: CompilerOptions compilerOptions = new CompilerOptions(options);
075: AssistOptions assistOptions = new AssistOptions(options);
076:
077: suggestNames(packageName, qualifiedTypeName, dim,
078: internalPrefix, assistOptions.localPrefixes,
079: assistOptions.localSuffixes, excludedNames,
080: getNameScanner(compilerOptions), requestor);
081: }
082:
083: private static void suggestNames(char[] packageName,
084: char[] qualifiedTypeName, int dim, char[] internalPrefix,
085: char[][] prefixes, char[][] suffixes,
086: char[][] excludedNames, Scanner nameScanner,
087: INamingRequestor requestor) {
088:
089: if (qualifiedTypeName == null || qualifiedTypeName.length == 0)
090: return;
091:
092: if (internalPrefix == null) {
093: internalPrefix = CharOperation.NO_CHAR;
094: } else {
095: internalPrefix = removePrefix(internalPrefix, prefixes);
096: }
097:
098: char[] typeName = CharOperation.lastSegment(qualifiedTypeName,
099: '.');
100:
101: if (prefixes == null || prefixes.length == 0) {
102: prefixes = new char[1][0];
103: } else {
104: int length = prefixes.length;
105: System.arraycopy(prefixes, 0,
106: prefixes = new char[length + 1][], 0, length);
107: prefixes[length] = CharOperation.NO_CHAR;
108: }
109:
110: if (suffixes == null || suffixes.length == 0) {
111: suffixes = new char[1][0];
112: } else {
113: int length = suffixes.length;
114: System.arraycopy(suffixes, 0,
115: suffixes = new char[length + 1][], 0, length);
116: suffixes[length] = CharOperation.NO_CHAR;
117: }
118:
119: char[][] tempNames = null;
120:
121: // compute variable name for base type
122: try {
123: nameScanner.setSource(typeName);
124: switch (nameScanner.getNextToken()) {
125: case TerminalTokens.TokenNameint:
126: case TerminalTokens.TokenNamebyte:
127: case TerminalTokens.TokenNameshort:
128: case TerminalTokens.TokenNamechar:
129: case TerminalTokens.TokenNamelong:
130: case TerminalTokens.TokenNamefloat:
131: case TerminalTokens.TokenNamedouble:
132: case TerminalTokens.TokenNameboolean:
133:
134: if (internalPrefix != null && internalPrefix.length > 0)
135: return;
136:
137: char[] name = computeBaseTypeNames(typeName[0],
138: excludedNames);
139: if (name != null) {
140: tempNames = new char[][] { name };
141: }
142: break;
143: }
144: } catch (InvalidInputException e) {
145: // ignore
146: }
147:
148: // compute variable name for non base type
149: if (tempNames == null) {
150: tempNames = computeNames(typeName);
151: }
152:
153: boolean acceptDefaultName = true;
154: SimpleSetOfCharArray foundNames = new SimpleSetOfCharArray();
155:
156: next: for (int i = 0; i < tempNames.length; i++) {
157: char[] tempName = tempNames[i];
158: if (dim > 0) {
159: int length = tempName.length;
160: if (tempName[length - 1] == 's') {
161: if (tempName.length > 1
162: && tempName[length - 2] == 's') {
163: System.arraycopy(tempName, 0,
164: tempName = new char[length + 2], 0,
165: length);
166: tempName[length] = 'e';
167: tempName[length + 1] = 's';
168: }
169: } else if (tempName[length - 1] == 'y') {
170: System.arraycopy(tempName, 0,
171: tempName = new char[length + 2], 0, length);
172: tempName[length - 1] = 'i';
173: tempName[length] = 'e';
174: tempName[length + 1] = 's';
175: } else {
176: System.arraycopy(tempName, 0,
177: tempName = new char[length + 1], 0, length);
178: tempName[length] = 's';
179: }
180: }
181:
182: char[] unprefixedName = tempName;
183: for (int j = 0; j <= internalPrefix.length; j++) {
184: if (j == internalPrefix.length
185: || CharOperation.prefixEquals(CharOperation
186: .subarray(internalPrefix, j, -1),
187: unprefixedName, false)) {
188: tempName = CharOperation.concat(CharOperation
189: .subarray(internalPrefix, 0, j),
190: unprefixedName);
191: if (j != 0)
192: tempName[j] = ScannerHelper
193: .toUpperCase(tempName[j]);
194: for (int k = 0; k < prefixes.length; k++) {
195: if (prefixes[k].length > 0
196: && ScannerHelper
197: .isLetterOrDigit(prefixes[k][prefixes[k].length - 1])) {
198: tempName[0] = ScannerHelper
199: .toUpperCase(tempName[0]);
200: } else {
201: tempName[0] = ScannerHelper
202: .toLowerCase(tempName[0]);
203: }
204: char[] prefixName = CharOperation.concat(
205: prefixes[k], tempName);
206: for (int l = 0; l < suffixes.length; l++) {
207: char[] suffixName = CharOperation.concat(
208: prefixName, suffixes[l]);
209: suffixName = excludeNames(suffixName,
210: prefixName, suffixes[l],
211: excludedNames);
212: try {
213: nameScanner.setSource(suffixName);
214: switch (nameScanner.getNextToken()) {
215: case TerminalTokens.TokenNameIdentifier:
216: int token = nameScanner
217: .getNextToken();
218: if (token == TerminalTokens.TokenNameEOF
219: && nameScanner.startPosition == suffixName.length) {
220: if (!foundNames
221: .includes(suffixName)) {
222: acceptName(
223: suffixName,
224: prefixes[k],
225: suffixes[l],
226: k == 0,
227: l == 0,
228: internalPrefix.length
229: - j,
230: requestor);
231: foundNames.add(suffixName);
232: acceptDefaultName = false;
233: }
234: }
235: break;
236: default:
237: suffixName = CharOperation.concat(
238: prefixName, String.valueOf(
239: 1).toCharArray(),
240: suffixes[l]);
241: suffixName = excludeNames(
242: suffixName, prefixName,
243: suffixes[l], excludedNames);
244: nameScanner.setSource(suffixName);
245: switch (nameScanner.getNextToken()) {
246: case TerminalTokens.TokenNameIdentifier:
247: token = nameScanner
248: .getNextToken();
249: if (token == TerminalTokens.TokenNameEOF
250: && nameScanner.startPosition == suffixName.length) {
251: if (!foundNames
252: .includes(suffixName)) {
253: acceptName(
254: suffixName,
255: prefixes[k],
256: suffixes[l],
257: k == 0,
258: l == 0,
259: internalPrefix.length
260: - j,
261: requestor);
262: foundNames
263: .add(suffixName);
264: acceptDefaultName = false;
265: }
266: }
267: }
268: }
269: } catch (InvalidInputException e) {
270: // ignore
271: }
272: }
273: }
274: continue next;
275: }
276: }
277: }
278: // if no names were found
279: if (acceptDefaultName) {
280: char[] name = excludeNames(DEFAULT_NAME, DEFAULT_NAME,
281: CharOperation.NO_CHAR, excludedNames);
282: requestor.acceptNameWithoutPrefixAndSuffix(name, 0);
283: }
284: }
285:
286: private static void acceptName(char[] name, char[] prefix,
287: char[] suffix, boolean isFirstPrefix,
288: boolean isFirstSuffix, int reusedCharacters,
289: INamingRequestor requestor) {
290: if (prefix.length > 0 && suffix.length > 0) {
291: requestor.acceptNameWithPrefixAndSuffix(name,
292: isFirstPrefix, isFirstSuffix, reusedCharacters);
293: } else if (prefix.length > 0) {
294: requestor.acceptNameWithPrefix(name, isFirstPrefix,
295: reusedCharacters);
296: } else if (suffix.length > 0) {
297: requestor.acceptNameWithSuffix(name, isFirstSuffix,
298: reusedCharacters);
299: } else {
300: requestor.acceptNameWithoutPrefixAndSuffix(name,
301: reusedCharacters);
302: }
303: }
304:
305: private static char[] computeBaseTypeNames(char firstName,
306: char[][] excludedNames) {
307: char[] name = new char[] { firstName };
308:
309: for (int i = 0; i < excludedNames.length; i++) {
310: if (CharOperation.equals(name, excludedNames[i], false)) {
311: name[0]++;
312: if (name[0] > 'z')
313: name[0] = 'a';
314: if (name[0] == firstName)
315: return null;
316: i = 0;
317: }
318: }
319:
320: return name;
321: }
322:
323: private static char[][] computeNames(char[] sourceName) {
324: char[][] names = new char[5][];
325: int nameCount = 0;
326: boolean previousIsUpperCase = false;
327: boolean previousIsLetter = true;
328: for (int i = sourceName.length - 1; i >= 0; i--) {
329: boolean isUpperCase = ScannerHelper
330: .isUpperCase(sourceName[i]);
331: boolean isLetter = ScannerHelper.isLetter(sourceName[i]);
332: if (isUpperCase && !previousIsUpperCase && previousIsLetter) {
333: char[] name = CharOperation.subarray(sourceName, i,
334: sourceName.length);
335: if (name.length > 1) {
336: if (nameCount == names.length) {
337: System.arraycopy(names, 0,
338: names = new char[nameCount * 2][], 0,
339: nameCount);
340: }
341: name[0] = ScannerHelper.toLowerCase(name[0]);
342: names[nameCount++] = name;
343: }
344: }
345: previousIsUpperCase = isUpperCase;
346: previousIsLetter = isLetter;
347: }
348: if (nameCount == 0) {
349: names[nameCount++] = CharOperation.toLowerCase(sourceName);
350: }
351: System.arraycopy(names, 0, names = new char[nameCount][], 0,
352: nameCount);
353: return names;
354: }
355:
356: private static char[] excludeNames(char[] suffixName,
357: char[] prefixName, char[] suffix, char[][] excludedNames) {
358: int count = 2;
359: int m = 0;
360: while (m < excludedNames.length) {
361: if (CharOperation.equals(suffixName, excludedNames[m],
362: false)) {
363: suffixName = CharOperation.concat(prefixName, String
364: .valueOf(count++).toCharArray(), suffix);
365: m = 0;
366: } else {
367: m++;
368: }
369: }
370: return suffixName;
371: }
372:
373: private static char[] removePrefix(char[] name, char[][] prefixes) {
374: // remove longer prefix
375: char[] withoutPrefixName = name;
376: if (prefixes != null) {
377: int bestLength = 0;
378: int nameLength = name.length;
379: for (int i = 0; i < prefixes.length; i++) {
380: char[] prefix = prefixes[i];
381:
382: int prefixLength = prefix.length;
383: if (prefixLength <= nameLength) {
384: if (CharOperation.prefixEquals(prefix, name, false)) {
385: if (prefixLength > bestLength) {
386: bestLength = prefixLength;
387: }
388: }
389: } else {
390: int currLen = 0;
391: for (; currLen < nameLength; currLen++) {
392: if (ScannerHelper.toLowerCase(prefix[currLen]) != ScannerHelper
393: .toLowerCase(name[currLen])) {
394: if (currLen > bestLength) {
395: bestLength = currLen;
396: }
397: break;
398: }
399: }
400: if (currLen == nameLength && currLen > bestLength) {
401: bestLength = currLen;
402: }
403: }
404: }
405: if (bestLength > 0) {
406: if (bestLength == nameLength) {
407: withoutPrefixName = CharOperation.NO_CHAR;
408: } else {
409: withoutPrefixName = CharOperation.subarray(name,
410: bestLength, nameLength);
411: }
412: }
413: }
414: //
415: //
416: // // remove longer prefix
417: // char[] withoutPrefixName = name;
418: // if (prefixes != null) {
419: // int bestLength = 0;
420: // for (int i= 0; i < prefixes.length; i++) {
421: // char[] prefix = prefixes[i];
422: // int max = prefix.length < name.length ? prefix.length : name.length;
423: // int currLen = 0;
424: // for (; currLen < max; currLen++) {
425: // if(Character.toLowerCase(prefix[currLen]) != Character.toLowerCase(name[currLen])) {
426: // if (currLen > bestLength) {
427: // bestLength = currLen;
428: // }
429: // break;
430: // }
431: // }
432: // if(currLen == max && currLen > bestLength) {
433: // bestLength = max;
434: // }
435: // }
436: // if(bestLength > 0) {
437: // if(bestLength == name.length) {
438: // withoutPrefixName = CharOperation.NO_CHAR;
439: // } else {
440: // withoutPrefixName = CharOperation.subarray(name, bestLength, name.length);
441: // }
442: // }
443: // }
444:
445: return withoutPrefixName;
446: }
447:
448: public static final boolean prefixEquals(char[] prefix, char[] name) {
449:
450: int max = prefix.length;
451: if (name.length < max)
452: return false;
453: for (int i = max; --i >= 0;)
454: // assumes the prefix is not larger than the name
455: if (prefix[i] != name[i])
456: return false;
457: return true;
458: }
459: }
|